From 8f0df92ba941837b898a2529e1f0e5016558ea5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Agneray?= <francois.agneray@lam.fr> Date: Wed, 21 Jul 2021 15:34:09 +0200 Subject: [PATCH] Cone-search => done --- .../criteria/cone-search-tab.component.html | 8 +- .../components/result/reminder.component.html | 4 +- .../components/result/reminder.component.ts | 9 +-- .../search/components/summary.component.html | 4 +- .../search/components/summary.component.ts | 9 +-- .../search/containers/criteria.component.html | 5 +- .../search/containers/dataset.component.html | 3 +- .../search/containers/output.component.html | 3 +- .../search/containers/result.component.html | 1 + .../cone-search/cone-search.component.html | 7 +- .../cone-search/cone-search.component.ts | 48 +++++++++++- .../components/cone-search/dec.component.html | 74 +++++++++--------- .../components/cone-search/dec.component.ts | 59 ++++++++------ .../components/cone-search/ra.component.html | 76 +++++++++---------- .../components/cone-search/ra.component.ts | 55 ++++++++------ .../cone-search/radius.component.html | 12 +-- .../cone-search/radius.component.ts | 7 +- .../cone-search/resolver.component.ts | 23 +++++- .../instance/store/effects/search.effects.ts | 41 ++++++++-- .../store/selectors/cone-search.selector.ts | 5 ++ .../store/selectors/search.selector.ts | 11 ++- server/src/Search/Query/ConeSearch.php | 6 +- 22 files changed, 296 insertions(+), 174 deletions(-) diff --git a/client/src/app/instance/search/components/criteria/cone-search-tab.component.html b/client/src/app/instance/search/components/criteria/cone-search-tab.component.html index 0e59b5ea..ea951c32 100644 --- a/client/src/app/instance/search/components/criteria/cone-search-tab.component.html +++ b/client/src/app/instance/search/components/criteria/cone-search-tab.component.html @@ -21,16 +21,16 @@ [resolverIsLoaded]="resolverIsLoaded" (addConeSearch)="addConeSearch.emit($event)" (deleteConeSearch)="deleteConeSearch.emit()" - (retrieveCoordinates)="retrieveCoordinates.emit($event)"> + (retrieveCoordinates)="retrieveCoordinates.emit($event)" #cs> </app-cone-search> </div> <div class="col-2 text-center align-self-end"> - <!-- <button class="btn btn-outline-success" *ngIf="!isConeSearchAdded" [hidden]="!isValidConeSearch" (click)="coneSearchAdded.emit(true)"> + <button class="btn btn-outline-success" *ngIf="!coneSearch" [hidden]="cs.form.invalid" (click)="addConeSearch.emit(cs.getConeSearch())"> <span class="fas fa-plus fa-fw"></span> </button> - <button class="btn btn-outline-danger" *ngIf="isConeSearchAdded" (click)="coneSearchAdded.emit(false)"> + <button class="btn btn-outline-danger" *ngIf="coneSearch" (click)="deleteConeSearch.emit()"> <span class="fa fa-times fa-fw"></span> - </button> --> + </button> </div> </div> </accordion-group> diff --git a/client/src/app/instance/search/components/result/reminder.component.html b/client/src/app/instance/search/components/result/reminder.component.html index d76e57d7..38372ace 100644 --- a/client/src/app/instance/search/components/result/reminder.component.html +++ b/client/src/app/instance/search/components/result/reminder.component.html @@ -24,14 +24,14 @@ </div> <div *ngIf="nbCriteria() > 0" class="row"> - <!-- <div *ngIf="isConeSearchAdded" class="col-12 col-md-6 col-xl-4 pb-3"> + <div *ngIf="coneSearch" class="col-12 col-md-6 col-xl-4 pb-3"> <span class="title">Cone search</span> <ul class="list-unstyled pl-3"> <li>RA = {{ coneSearch.ra }}°</li> <li>DEC = {{ coneSearch.dec }}°</li> <li>radius = {{ coneSearch.radius }} arcsecond</li> </ul> - </div> --> + </div> <ng-container *ngFor="let family of criteriaFamilyList"> <ng-container *ngIf="criteriaByFamily(family.id).length > 0"> diff --git a/client/src/app/instance/search/components/result/reminder.component.ts b/client/src/app/instance/search/components/result/reminder.component.ts index 9961ece0..8e3d88ea 100644 --- a/client/src/app/instance/search/components/result/reminder.component.ts +++ b/client/src/app/instance/search/components/result/reminder.component.ts @@ -28,9 +28,8 @@ export class ReminderComponent { @Input() criteriaFamilyList: CriteriaFamily[]; @Input() outputFamilyList: OutputFamily[]; @Input() outputCategoryList: OutputCategory[]; - // @Input() isConeSearchAdded: boolean; - // @Input() coneSearch: ConeSearch; @Input() criteriaList: Criterion[]; + @Input() coneSearch: ConeSearch; @Input() outputList: number[]; isSummaryActivated(): boolean { @@ -49,9 +48,9 @@ export class ReminderComponent { * @return number */ nbCriteria(): number { - // if (this.isConeSearchAdded) { - // return this.criteriaList.length + 1; - // } + if (this.coneSearch) { + return this.criteriaList.length + 1; + } return this.criteriaList.length; } diff --git a/client/src/app/instance/search/components/summary.component.html b/client/src/app/instance/search/components/summary.component.html index 0fc5455e..86c376fb 100644 --- a/client/src/app/instance/search/components/summary.component.html +++ b/client/src/app/instance/search/components/summary.component.html @@ -15,14 +15,14 @@ <p *ngIf="noCriteria()" class="pl-5 font-weight-bold"> No selected criteria </p> - <!-- <span *ngIf="isConeSearchAdded" class="pl-5"> + <span *ngIf="coneSearch" class="pl-5"> Cone search: <ul class="ml-3 pl-5 list-unstyled"> <li>RA = {{ coneSearch.ra }}°</li> <li>DEC = {{ coneSearch.dec }}°</li> <li>radius = {{ coneSearch.radius }} arcsecond</li> </ul> - </span> --> + </span> <ul *ngIf="criteriaList.length > 0" class="pl-5 list-unstyled"> <li *ngFor="let criterion of criteriaList"> {{ getAttribute(criterion.id).form_label }} {{ printCriterion(criterion) }} diff --git a/client/src/app/instance/search/components/summary.component.ts b/client/src/app/instance/search/components/summary.component.ts index dfa03f44..3e76c627 100644 --- a/client/src/app/instance/search/components/summary.component.ts +++ b/client/src/app/instance/search/components/summary.component.ts @@ -9,9 +9,8 @@ import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core'; -import { Criterion, SearchQueryParams, getPrettyCriterion } from '../../store/models'; +import { Criterion, ConeSearch, SearchQueryParams, getPrettyCriterion } from '../../store/models'; import { Attribute, Dataset, CriteriaFamily, OutputFamily, OutputCategory } from 'src/app/metamodel/models'; -// import { ConeSearch } from '../../shared/cone-search/store/model'; @Component({ selector: 'app-summary', @@ -27,8 +26,6 @@ export class SummaryComponent { @Input() currentStep: string; @Input() datasetSelected: string; @Input() datasetList: Dataset[]; - // @Input() isConeSearchAdded: boolean; - // @Input() coneSearch: ConeSearch; @Input() attributeList: Attribute[]; @Input() criteriaFamilyList: CriteriaFamily[]; @Input() outputFamilyList: OutputFamily[]; @@ -36,6 +33,7 @@ export class SummaryComponent { @Input() criteriaList: Criterion[]; @Input() outputList: number[]; @Input() queryParams: SearchQueryParams; + @Input() coneSearch: ConeSearch; accordionFamilyIsOpen = true; @@ -54,8 +52,7 @@ export class SummaryComponent { * @return boolean */ noCriteria(): boolean { - //if (this.isConeSearchAdded || this.criteriaList.length > 0) { - if (this.criteriaList.length > 0) { + if (this.coneSearch || this.criteriaList.length > 0) { return false } return true; diff --git a/client/src/app/instance/search/containers/criteria.component.html b/client/src/app/instance/search/containers/criteria.component.html index 0c52d16c..8ff2d1d9 100644 --- a/client/src/app/instance/search/containers/criteria.component.html +++ b/client/src/app/instance/search/containers/criteria.component.html @@ -38,7 +38,8 @@ [outputCategoryList]="outputCategoryList | async" [criteriaList]="criteriaList | async" [outputList]="outputList | async" - [queryParams]="queryParams | async"> + [queryParams]="queryParams | async" + [coneSearch]="coneSearch | async"> </app-summary> </div> </div> @@ -51,7 +52,7 @@ </a> </div> <div class="col col-auto"> - <a routerLink="/search/output/{{ datasetSelected | async }}" [queryParams]="queryParams | async" + <a routerLink="/instance/{{ instanceSelected | async }}/search/output/{{ datasetSelected | async }}" [queryParams]="queryParams | async" class="btn btn-outline-primary"> Output <span class="fas fa-arrow-right"></span> </a> diff --git a/client/src/app/instance/search/containers/dataset.component.html b/client/src/app/instance/search/containers/dataset.component.html index b86d5815..77107988 100644 --- a/client/src/app/instance/search/containers/dataset.component.html +++ b/client/src/app/instance/search/containers/dataset.component.html @@ -36,7 +36,8 @@ [outputCategoryList]="outputCategoryList | async" [criteriaList]="criteriaList | async" [outputList]="outputList | async" - [queryParams]="queryParams | async"> + [queryParams]="queryParams | async" + [coneSearch]="coneSearch | async"> </app-summary> </div> </ng-container> diff --git a/client/src/app/instance/search/containers/output.component.html b/client/src/app/instance/search/containers/output.component.html index 9b0cdec4..12d7f605 100644 --- a/client/src/app/instance/search/containers/output.component.html +++ b/client/src/app/instance/search/containers/output.component.html @@ -27,7 +27,8 @@ [outputCategoryList]="outputCategoryList | async" [criteriaList]="criteriaList | async" [outputList]="outputList | async" - [queryParams]="queryParams | async"> + [queryParams]="queryParams | async" + [coneSearch]="coneSearch | async"> </app-summary> </div> </div> diff --git a/client/src/app/instance/search/containers/result.component.html b/client/src/app/instance/search/containers/result.component.html index 9eacc2ff..ab045ae2 100644 --- a/client/src/app/instance/search/containers/result.component.html +++ b/client/src/app/instance/search/containers/result.component.html @@ -36,6 +36,7 @@ [outputFamilyList]="outputFamilyList | async" [outputCategoryList]="outputCategoryList | async" [criteriaList]="criteriaList | async" + [coneSearch]="coneSearch | async" [outputList]="outputList | async"> </app-reminder> <app-samp diff --git a/client/src/app/instance/shared-search/components/cone-search/cone-search.component.html b/client/src/app/instance/shared-search/components/cone-search/cone-search.component.html index 1aa2ee2e..6e676e97 100644 --- a/client/src/app/instance/shared-search/components/cone-search/cone-search.component.html +++ b/client/src/app/instance/shared-search/components/cone-search/cone-search.component.html @@ -1,6 +1,7 @@ <div class="row pb-4"> <div class="col"> <app-resolver + [coneSearch]="coneSearch" [resolver]="resolver" [resolverIsLoading]="resolverIsLoading" [resolverIsLoaded]="resolverIsLoaded" @@ -10,16 +11,16 @@ </div> <div class="row"> <div class="col pb-4"> - <app-ra [form]="form" [unit]="unit"> + <app-ra [form]="form" [unit]="unit" [resolver]="resolver"> </app-ra> </div> <div class="col-auto p-0 align-self-center"> - <button class="btn btn-outline-secondary" (click)="unit === 'degree' ? unit = 'hms' : unit = 'degree'" title="Change unit"> + <button class="btn btn-outline-secondary" [disabled]="coneSearch" (click)="unit === 'degree' ? unit = 'hms' : unit = 'degree'" title="Change unit"> <span class="fas fa-sync-alt"></span> </button> </div> <div class="col"> - <app-dec [form]="form" [unit]="unit"> + <app-dec [form]="form" [unit]="unit" [resolver]="resolver"> </app-dec> </div> <div class="col-12"> diff --git a/client/src/app/instance/shared-search/components/cone-search/cone-search.component.ts b/client/src/app/instance/shared-search/components/cone-search/cone-search.component.ts index a03c9bc8..ca589c83 100644 --- a/client/src/app/instance/shared-search/components/cone-search/cone-search.component.ts +++ b/client/src/app/instance/shared-search/components/cone-search/cone-search.component.ts @@ -7,7 +7,7 @@ * file that was distributed with this source code. */ -import { Component, Input, Output, EventEmitter } from '@angular/core'; +import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { ConeSearch, Resolver } from 'src/app/instance/store/models'; @@ -21,7 +21,7 @@ import { nanValidator, rangeValidator } from '../../validators'; * @class * @classdesc Cone search container. */ -export class ConeSearchComponent { +export class ConeSearchComponent implements OnChanges { @Input() coneSearch: ConeSearch; @Input() resolver: Resolver; @Input() resolverIsLoading: boolean; @@ -32,9 +32,49 @@ export class ConeSearchComponent { public form = new FormGroup({ ra: new FormControl('', [Validators.required, nanValidator, rangeValidator(0, 360, 'RA')]), + ra_hms: new FormGroup({ + h: new FormControl('', [Validators.required, nanValidator, rangeValidator(0, 24, 'Hours')]), + m: new FormControl('', [Validators.required, nanValidator, rangeValidator(0, 60, 'Minutes')]), + s: new FormControl('', [Validators.required, nanValidator, rangeValidator(0, 60, 'Seconds')]) + }), dec: new FormControl('', [Validators.required, nanValidator, rangeValidator(-90, 90, 'DEC')]), - radius: new FormControl('', [rangeValidator(0, 150, 'Radius')]) + dec_dms: new FormGroup({ + d: new FormControl('', [Validators.required, nanValidator, rangeValidator(-90, 90, 'Degree')]), + m: new FormControl('', [Validators.required, nanValidator, rangeValidator(0, 60, 'Minutes')]), + s: new FormControl('', [Validators.required, nanValidator, rangeValidator(0, 60, 'Seconds')]) + }), + radius: new FormControl(2, [Validators.required, rangeValidator(0, 150, 'Radius')]) }); - unit = 'degree'; + public unit = 'degree'; + + ngOnChanges(changes: SimpleChanges) { + if (changes.resolver && changes.resolver.currentValue) { + this.unit = 'degree'; + } + + if (changes.coneSearch && !changes.coneSearch.currentValue) { + if (this.unit = 'degree') { + this.form.controls.ra.enable(); + this.form.controls.dec.enable(); + this.form.controls.radius.enable(); + } else { + this.form.controls.ra_hms.enable(); + this.form.controls.dec_dms.enable(); + } + } + + if (changes.coneSearch && changes.coneSearch.currentValue) { + this.form.patchValue(this.coneSearch); + this.form.disable(); + } + } + + getConeSearch(): ConeSearch { + return { + ra: this.form.controls.ra.value, + dec: this.form.controls.dec.value, + radius: this.form.controls.radius.value + }; + } } diff --git a/client/src/app/instance/shared-search/components/cone-search/dec.component.html b/client/src/app/instance/shared-search/components/cone-search/dec.component.html index 62735e6e..c8fe7677 100644 --- a/client/src/app/instance/shared-search/components/cone-search/dec.component.html +++ b/client/src/app/instance/shared-search/components/cone-search/dec.component.html @@ -8,33 +8,33 @@ </div> </div> </div> -</form> -<form [formGroup]="dmsForm" novalidate> - <div class="row mt-2 px-3"> - <div class="col px-0 pr-xl-1"> - <div class="input-group"> - <input type="number" class="form-control" formControlName="decD" autocomplete="off"> - <div class="input-group-append"> - <span class="input-group-text">°</span> + <div formGroupName="dec_dms"> + <div class="row mt-2 px-3"> + <div class="col px-0 pr-xl-1"> + <div class="input-group"> + <input type="number" class="form-control" formControlName="d" autocomplete="off"> + <div class="input-group-append"> + <span class="input-group-text">°</span> + </div> </div> </div> - </div> - <div class="w-100 d-block d-xl-none"></div> - <div class="col mt-1 mt-xl-auto px-0 pr-xl-1"> - <div class="input-group"> - <input type="number" class="form-control" formControlName="decM" autocomplete="off"> - <div class="input-group-append"> - <span class="input-group-text">'</span> + <div class="w-100 d-block d-xl-none"></div> + <div class="col mt-1 mt-xl-auto px-0 pr-xl-1"> + <div class="input-group"> + <input type="number" class="form-control" formControlName="m" autocomplete="off"> + <div class="input-group-append"> + <span class="input-group-text">'</span> + </div> </div> </div> - </div> - <div class="w-100 d-block d-xl-none"></div> - <div class="col mt-1 mt-xl-auto px-0"> - <div class="input-group"> - <input type="number" class="form-control" formControlName="decS" autocomplete="off"> - <div class="input-group-append"> - <span class="input-group-text">''</span> + <div class="w-100 d-block d-xl-none"></div> + <div class="col mt-1 mt-xl-auto px-0"> + <div class="input-group"> + <input type="number" class="form-control" formControlName="s" autocomplete="off"> + <div class="input-group-append"> + <span class="input-group-text">''</span> + </div> </div> </div> </div> @@ -49,27 +49,27 @@ {{ form.controls.dec.errors.range.value }} </div> </div> -<div *ngIf="dmsForm.controls.decD.invalid" class="row px-3 text-danger"> - <div *ngIf="dmsForm.controls.decD.errors.nan"> - {{ dmsForm.controls.decD.errors.nan.value }} +<div *ngIf="getDecDmsForm().controls.d.invalid" class="row px-3 text-danger"> + <div *ngIf="getDecDmsForm().controls.d.errors.nan"> + {{ getDecDmsForm().controls.d.errors.nan.value }} </div> - <div *ngIf="dmsForm.controls.decD.errors.range" [hidden]="dmsForm.controls.decD.errors.nan"> - {{ dmsForm.controls.decD.errors.range.value }} + <div *ngIf="getDecDmsForm().controls.d.errors.range" [hidden]="getDecDmsForm().controls.d.errors.nan"> + {{ getDecDmsForm().controls.d.errors.range.value }} </div> </div> -<div *ngIf="dmsForm.controls.decM.invalid" class="row px-3 text-danger"> - <div *ngIf="dmsForm.controls.decM.errors.nan"> - {{ dmsForm.controls.decM.errors.nan.value }} +<div *ngIf="getDecDmsForm().controls.m.invalid" class="row px-3 text-danger"> + <div *ngIf="getDecDmsForm().controls.m.errors.nan"> + {{ getDecDmsForm().controls.m.errors.nan.value }} </div> - <div *ngIf="dmsForm.controls.decM.errors.range" [hidden]="dmsForm.controls.decM.errors.nan"> - {{ dmsForm.controls.decM.errors.range.value }} + <div *ngIf="getDecDmsForm().controls.m.errors.range" [hidden]="getDecDmsForm().controls.m.errors.nan"> + {{ getDecDmsForm().controls.m.errors.range.value }} </div> </div> -<div *ngIf="dmsForm.controls.decS.invalid" class="row px-3 text-danger"> - <div *ngIf="dmsForm.controls.decS.errors.nan"> - {{ dmsForm.controls.decS.errors.nan.value }} +<div *ngIf="getDecDmsForm().controls.s.invalid" class="row px-3 text-danger"> + <div *ngIf="getDecDmsForm().controls.s.errors.nan"> + {{ getDecDmsForm().controls.s.errors.nan.value }} </div> - <div *ngIf="dmsForm.controls.decS.errors.range" [hidden]="dmsForm.controls.decS.errors.nan"> - {{ dmsForm.controls.decS.errors.range.value }} + <div *ngIf="getDecDmsForm().controls.s.errors.range" [hidden]="getDecDmsForm().controls.s.errors.nan"> + {{ getDecDmsForm().controls.s.errors.range.value }} </div> </div> diff --git a/client/src/app/instance/shared-search/components/cone-search/dec.component.ts b/client/src/app/instance/shared-search/components/cone-search/dec.component.ts index f5d4c149..193bc665 100644 --- a/client/src/app/instance/shared-search/components/cone-search/dec.component.ts +++ b/client/src/app/instance/shared-search/components/cone-search/dec.component.ts @@ -7,13 +7,13 @@ * file that was distributed with this source code. */ -import { Component, Input, ChangeDetectionStrategy, OnDestroy, OnChanges, SimpleChanges } from '@angular/core'; -import { FormGroup, FormControl } from '@angular/forms'; +import { Component, Input, ChangeDetectionStrategy, OnInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core'; +import { FormGroup } from '@angular/forms'; import { Subscription } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; -import { nanValidator, rangeValidator } from '../../validators'; +import { Resolver } from 'src/app/instance/store/models'; @Component({ selector: 'app-dec', @@ -25,36 +25,46 @@ import { nanValidator, rangeValidator } from '../../validators'; * @class * @classdesc DEC component. */ -export class DecComponent implements OnDestroy, OnChanges { +export class DecComponent implements OnInit, OnDestroy, OnChanges { @Input() form: FormGroup; @Input() unit: string; - - public dmsForm = new FormGroup({ - decD: new FormControl('', [nanValidator, rangeValidator(-90, 90, 'Degree')]), - decM: new FormControl('', [nanValidator, rangeValidator(0, 60, 'Minutes')]), - decS: new FormControl('', [nanValidator, rangeValidator(0, 60, 'Seconds')]) - }); + @Input() resolver: Resolver; public decControlSubscription: Subscription - public dmsFormSubscription: Subscription; + public decDmsSubscription: Subscription; + + ngOnInit() { + this.form.controls.dec_dms.disable(); + this.decControlSubscription = this.form.controls.dec.valueChanges.pipe(debounceTime(250)) + .subscribe(deg => this.deg2DMS(deg)); + } ngOnChanges(changes: SimpleChanges): void { - if (changes.unit) { + if (changes.unit && !changes.unit.firstChange) { if (changes.unit.currentValue === 'degree') { - this.dmsForm.disable(); + this.form.controls.dec_dms.disable(); this.form.controls.dec.enable(); this.decControlSubscription = this.form.controls.dec.valueChanges.pipe(debounceTime(250)) .subscribe(deg => this.deg2DMS(deg)); - if (this.dmsFormSubscription) this.dmsFormSubscription.unsubscribe(); + if (this.decDmsSubscription) this.decDmsSubscription.unsubscribe(); } if (changes.unit.currentValue === 'hms') { - this.dmsForm.enable(); + this.form.controls.dec_dms.enable(); this.form.controls.dec.disable(); - this.dmsFormSubscription = this.dmsForm.valueChanges.pipe(debounceTime(250)) + this.decDmsSubscription = this.form.controls.dec_dms.valueChanges.pipe(debounceTime(250)) .subscribe(value => this.DMS2Deg(value)); if (this.decControlSubscription) this.decControlSubscription.unsubscribe(); } } + + if (changes.resolver && changes.resolver.currentValue) { + this.form.controls.dec.setValue(changes.resolver.currentValue.dec); + } + } + + getDecDmsForm() { + const decDmsForm = this.form.controls.dec_dms as FormGroup; + return decDmsForm; } deg2DMS(deg: number): void { @@ -63,15 +73,16 @@ export class DecComponent implements OnDestroy, OnChanges { const mm = Math.trunc(tmp); tmp = (tmp - mm) * 60; const ss = tmp.toFixed(2); - this.dmsForm.controls.decD.setValue(hh); - this.dmsForm.controls.decM.setValue(mm); - this.dmsForm.controls.decS.setValue(ss); + const decDmsForm = this.getDecDmsForm(); + decDmsForm.controls.d.setValue(hh); + decDmsForm.controls.m.setValue(mm); + decDmsForm.controls.s.setValue(ss); } - DMS2Deg(dms: {decD: number, decM: number, decS: number }): void { - const tmp = ((dms.decS / 60) + dms.decM) / 60; - let deg = tmp + Math.abs(dms.decD); - if (dms.decD < 0) { + DMS2Deg(dms: {d: number, m: number, s: number }): void { + const tmp = ((dms.s / 60) + dms.m) / 60; + let deg = tmp + Math.abs(dms.d); + if (dms.d < 0) { deg = -deg; } this.form.controls.dec.setValue(deg); @@ -79,6 +90,6 @@ export class DecComponent implements OnDestroy, OnChanges { ngOnDestroy() { if (this.decControlSubscription) this.decControlSubscription.unsubscribe(); - if (this.dmsFormSubscription) this.dmsFormSubscription.unsubscribe(); + if (this.decDmsSubscription) this.decDmsSubscription.unsubscribe(); } } diff --git a/client/src/app/instance/shared-search/components/cone-search/ra.component.html b/client/src/app/instance/shared-search/components/cone-search/ra.component.html index cb81ae28..bb180bf8 100644 --- a/client/src/app/instance/shared-search/components/cone-search/ra.component.html +++ b/client/src/app/instance/shared-search/components/cone-search/ra.component.html @@ -8,33 +8,33 @@ </div> </div> </div> -</form> -<form [formGroup]="hmsForm" novalidate> - <div class="row mt-2 px-3"> - <div class="col px-0 pr-xl-1"> - <div class="input-group"> - <input type="number" class="form-control" formControlName="raH" autocomplete="off"> - <div class="input-group-append"> - <span class="input-group-text">H</span> + <div formGroupName="ra_hms"> + <div class="row mt-2 px-3"> + <div class="col px-0 pr-xl-1"> + <div class="input-group"> + <input type="number" class="form-control" formControlName="h" autocomplete="off"> + <div class="input-group-append"> + <span class="input-group-text">H</span> + </div> </div> </div> - </div> - <div class="w-100 d-block d-xl-none"></div> - <div class="col mt-1 mt-xl-auto px-0 pr-xl-1"> - <div class="input-group"> - <input type="number" class="form-control" formControlName="raM" autocomplete="off"> - <div class="input-group-append"> - <span class="input-group-text">'</span> + <div class="w-100 d-block d-xl-none"></div> + <div class="col mt-1 mt-xl-auto px-0 pr-xl-1"> + <div class="input-group"> + <input type="number" class="form-control" formControlName="m" autocomplete="off"> + <div class="input-group-append"> + <span class="input-group-text">'</span> + </div> </div> </div> - </div> - <div class="w-100 d-block d-xl-none"></div> - <div class="col mt-1 mt-xl-auto px-0"> - <div class="input-group"> - <input type="number" class="form-control" formControlName="raS" autocomplete="off"> - <div class="input-group-append"> - <span class="input-group-text">''</span> + <div class="w-100 d-block d-xl-none"></div> + <div class="col mt-1 mt-xl-auto px-0"> + <div class="input-group"> + <input type="number" class="form-control" formControlName="s" autocomplete="off"> + <div class="input-group-append"> + <span class="input-group-text">''</span> + </div> </div> </div> </div> @@ -49,27 +49,27 @@ {{ form.controls.ra.errors.range.value }} </div> </div> -<div *ngIf="hmsForm.controls.raH.invalid" class="row px-3 text-danger"> - <div *ngIf="hmsForm.controls.raH.errors.nan"> - {{ hmsForm.controls.raH.errors.nan.value }} +<div *ngIf="getRaHmsForm().controls.h.invalid" class="row px-3 text-danger"> + <div *ngIf="getRaHmsForm().controls.h.errors.nan"> + {{ getRaHmsForm().controls.h.errors.nan.value }} </div> - <div *ngIf="hmsForm.controls.raH.errors.range" [hidden]="hmsForm.controls.raH.errors.nan"> - {{ hmsForm.controls.raH.errors.range.value }} + <div *ngIf="getRaHmsForm().controls.h.errors.range" [hidden]="getRaHmsForm().controls.h.errors.nan"> + {{ getRaHmsForm().controls.h.errors.range.value }} </div> </div> -<div *ngIf="hmsForm.controls.raM.invalid" class="row px-3 text-danger"> - <div *ngIf="hmsForm.controls.raM.errors.nan"> - {{ hmsForm.controls.raM.errors.nan.value }} +<div *ngIf="getRaHmsForm().controls.m.invalid" class="row px-3 text-danger"> + <div *ngIf="getRaHmsForm().controls.m.errors.nan"> + {{ getRaHmsForm().controls.m.errors.nan.value }} </div> - <div *ngIf="hmsForm.controls.raM.errors.range" [hidden]="hmsForm.controls.raM.errors.nan"> - {{ hmsForm.controls.raM.errors.range.value }} + <div *ngIf="getRaHmsForm().controls.m.errors.range" [hidden]="getRaHmsForm().controls.m.errors.nan"> + {{ getRaHmsForm().controls.m.errors.range.value }} </div> </div> -<div *ngIf="hmsForm.controls.raS.invalid" class="row px-3 text-danger"> - <div *ngIf="hmsForm.controls.raS.errors.nan"> - {{ hmsForm.controls.raS.errors.nan.value }} +<div *ngIf="getRaHmsForm().controls.s.invalid" class="row px-3 text-danger"> + <div *ngIf="getRaHmsForm().controls.s.errors.nan"> + {{ getRaHmsForm().controls.s.errors.nan.value }} </div> - <div *ngIf="hmsForm.controls.raS.errors.range" [hidden]="hmsForm.controls.raS.errors.nan"> - {{ hmsForm.controls.raS.errors.range.value }} + <div *ngIf="getRaHmsForm().controls.s.errors.range" [hidden]="getRaHmsForm().controls.s.errors.nan"> + {{ getRaHmsForm().controls.s.errors.range.value }} </div> -</div> \ No newline at end of file +</div> diff --git a/client/src/app/instance/shared-search/components/cone-search/ra.component.ts b/client/src/app/instance/shared-search/components/cone-search/ra.component.ts index d572c02a..aab36bf7 100644 --- a/client/src/app/instance/shared-search/components/cone-search/ra.component.ts +++ b/client/src/app/instance/shared-search/components/cone-search/ra.component.ts @@ -7,13 +7,13 @@ * file that was distributed with this source code. */ -import { Component, Input, ChangeDetectionStrategy, OnDestroy, OnChanges, SimpleChanges } from '@angular/core'; -import { FormGroup, FormControl } from '@angular/forms'; +import { Component, Input, ChangeDetectionStrategy, OnDestroy, OnInit, OnChanges, SimpleChanges } from '@angular/core'; +import { FormGroup } from '@angular/forms'; import { Subscription } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; -import { nanValidator, rangeValidator } from '../../validators'; +import { Resolver } from 'src/app/instance/store/models'; @Component({ selector: 'app-ra', @@ -25,36 +25,46 @@ import { nanValidator, rangeValidator } from '../../validators'; * @class * @classdesc RA component. */ -export class RaComponent implements OnDestroy, OnChanges { +export class RaComponent implements OnInit, OnDestroy, OnChanges { @Input() form: FormGroup; @Input() unit: string; - - public hmsForm = new FormGroup({ - raH: new FormControl('', [nanValidator, rangeValidator(0, 24, 'Hours')]), - raM: new FormControl('', [nanValidator, rangeValidator(0, 60, 'Minutes')]), - raS: new FormControl('', [nanValidator, rangeValidator(0, 60, 'Seconds')]) - }); + @Input() resolver: Resolver; public raControlSubscription: Subscription; - public hmsFormSubscription: Subscription; + public raHmsFormSubscription: Subscription; + + ngOnInit() { + this.form.controls.ra_hms.disable(); + this.raControlSubscription = this.form.controls.ra.valueChanges.pipe(debounceTime(250)) + .subscribe(deg => this.deg2HMS(deg)); + } ngOnChanges(changes: SimpleChanges): void { - if (changes.unit) { + if (changes.unit && !changes.unit.firstChange) { if (changes.unit.currentValue === 'degree') { - this.hmsForm.disable(); + this.form.controls.ra_hms.disable(); this.form.controls.ra.enable(); this.raControlSubscription = this.form.controls.ra.valueChanges.pipe(debounceTime(250)) .subscribe(deg => this.deg2HMS(deg)); - if (this.hmsFormSubscription) this.hmsFormSubscription.unsubscribe(); + if (this.raHmsFormSubscription) this.raHmsFormSubscription.unsubscribe(); } if (changes.unit.currentValue === 'hms') { - this.hmsForm.enable(); + this.form.controls.ra_hms.enable(); this.form.controls.ra.disable(); - this.hmsFormSubscription = this.hmsForm.valueChanges.pipe(debounceTime(250)) + this.raHmsFormSubscription = this.form.controls.ra_hms.valueChanges.pipe(debounceTime(250)) .subscribe(value => this.HMS2Deg(value)); if (this.raControlSubscription) this.raControlSubscription.unsubscribe(); } } + + if (changes.resolver && changes.resolver.currentValue) { + this.form.controls.ra.setValue(changes.resolver.currentValue.ra); + } + } + + getRaHmsForm() { + const raHmsForm = this.form.controls.ra_hms as FormGroup; + return raHmsForm; } deg2HMS(deg: number): void { @@ -64,18 +74,19 @@ export class RaComponent implements OnDestroy, OnChanges { const mm = Math.trunc(tmp); tmp = (tmp - mm) * 60; const ss = +tmp.toFixed(2); - this.hmsForm.controls.raH.setValue(hh); - this.hmsForm.controls.raM.setValue(mm); - this.hmsForm.controls.raS.setValue(ss); + const raHmsForm = this.getRaHmsForm(); + raHmsForm.controls.h.setValue(hh); + raHmsForm.controls.m.setValue(mm); + raHmsForm.controls.s.setValue(ss); } - HMS2Deg(hms: {raH: number, raM: number, raS: number }): void { - const deg = +(((((hms.raS / 60) + hms.raM) / 60) + hms.raH) * 15).toFixed(8); + HMS2Deg(hms: {h: number, m: number, s: number }): void { + const deg = +(((((hms.s / 60) + hms.m) / 60) + hms.h) * 15).toFixed(8); this.form.controls.ra.setValue(deg); } ngOnDestroy() { if (this.raControlSubscription) this.raControlSubscription.unsubscribe(); - if (this.hmsFormSubscription) this.hmsFormSubscription.unsubscribe(); + if (this.raHmsFormSubscription) this.raHmsFormSubscription.unsubscribe(); } } diff --git a/client/src/app/instance/shared-search/components/cone-search/radius.component.html b/client/src/app/instance/shared-search/components/cone-search/radius.component.html index 052da446..87cdf7a2 100644 --- a/client/src/app/instance/shared-search/components/cone-search/radius.component.html +++ b/client/src/app/instance/shared-search/components/cone-search/radius.component.html @@ -2,21 +2,21 @@ <div class="row"> <div class="col form-group mb-0"> <label>Radius</label> - <input type="range" min="0" max="150" class="form-control-range mt-2" autocomplete="off"> + <input type="range" min="0" max="150" class="form-control-range mt-2" [value]="form.value.radius" formControlName="radius" autocomplete="off"> </div> <div class="w-100 d-block d-lg-none"></div> <div class="col col-lg-auto form-group mb-0"> <div class="input-group mt-4"> - <input type="number" class="form-control" formControlName="radius" autocomplete="off"> + <input type="number" class="form-control" [value]="form.value.radius" formControlName="radius" autocomplete="off"> <div class="input-group-append"> <span class="input-group-text">arcsecond</span> </div> </div> </div> - <!-- <div *ngIf="radiusField.invalid" class="col-12 text-danger"> - <div *ngIf="radiusField.errors.range"> - {{ radiusField.errors.range.value }} + <div *ngIf="form.controls.radius.invalid" class="col-12 text-danger"> + <div *ngIf="form.controls.radius.errors.range"> + {{ form.controls.radius.errors.range.value }} </div> - </div> --> + </div> </div> </form> \ No newline at end of file diff --git a/client/src/app/instance/shared-search/components/cone-search/radius.component.ts b/client/src/app/instance/shared-search/components/cone-search/radius.component.ts index b0678ccc..fde6ceb2 100644 --- a/client/src/app/instance/shared-search/components/cone-search/radius.component.ts +++ b/client/src/app/instance/shared-search/components/cone-search/radius.component.ts @@ -7,11 +7,8 @@ * file that was distributed with this source code. */ -import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'; -import { FormGroup, FormControl } from '@angular/forms'; - -import { rangeValidator } from '../../validators'; -import { ConeSearch } from 'src/app/instance/store/models'; +import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; +import { FormGroup } from '@angular/forms'; @Component({ selector: 'app-radius', diff --git a/client/src/app/instance/shared-search/components/cone-search/resolver.component.ts b/client/src/app/instance/shared-search/components/cone-search/resolver.component.ts index fb9a1635..18c09444 100644 --- a/client/src/app/instance/shared-search/components/cone-search/resolver.component.ts +++ b/client/src/app/instance/shared-search/components/cone-search/resolver.component.ts @@ -7,10 +7,10 @@ * file that was distributed with this source code. */ -import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'; +import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, OnInit, OnChanges, SimpleChanges } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; -import { Resolver } from 'src/app/instance/store/models'; +import { ConeSearch, Resolver } from 'src/app/instance/store/models'; @Component({ selector: 'app-resolver', @@ -21,7 +21,8 @@ import { Resolver } from 'src/app/instance/store/models'; * @class * @classdesc Resolver component. */ -export class ResolverComponent { +export class ResolverComponent implements OnInit, OnChanges { + @Input() coneSearch: ConeSearch; @Input() resolver: Resolver; @Input() resolverIsLoading: boolean; @Input() resolverIsLoaded: boolean; @@ -31,6 +32,22 @@ export class ResolverComponent { name: new FormControl('', [Validators.required]) }); + ngOnInit() { + if (this.coneSearch) { + this.form.disable(); + } + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.coneSearch && !changes.coneSearch.currentValue) { + this.form.enable(); + } + + if (changes.coneSearch && changes.coneSearch.currentValue) { + this.form.disable(); + } + } + submit() { this.retrieveCoordinates.emit(this.form.controls.name.value); } diff --git a/client/src/app/instance/store/effects/search.effects.ts b/client/src/app/instance/store/effects/search.effects.ts index f3ffcd4d..b92513c6 100644 --- a/client/src/app/instance/store/effects/search.effects.ts +++ b/client/src/app/instance/store/effects/search.effects.ts @@ -15,7 +15,7 @@ import { of } from 'rxjs'; import { map, tap, mergeMap, catchError } from 'rxjs/operators'; import { ToastrService } from 'ngx-toastr'; -import { criterionToString, stringToCriterion } from '../models'; +import { ConeSearch, criterionToString, stringToCriterion } from '../models'; import { SearchService } from '../services/search.service'; import * as searchActions from '../actions/search.actions'; import * as attributeActions from 'src/app/metamodel/actions/attribute.actions'; @@ -25,6 +25,8 @@ import * as outputFamilyActions from 'src/app/metamodel/actions/output-family.ac import * as outputCategoryActions from 'src/app/metamodel/actions/output-category.actions'; import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; import * as searchSelector from '../selectors/search.selector'; +import * as coneSearchActions from '../actions/cone-search.actions'; +import * as coneSearchSelector from '../selectors/cone-search.selector'; @Injectable() export class SearchEffects { @@ -88,11 +90,19 @@ export class SearchEffects { this.actions$.pipe( ofType(searchActions.loadDefaultFormParameters), concatLatestFrom(() => [ + this.store.select(searchSelector.selectPristine), + this.store.select(searchSelector.selectCurrentDataset), this.store.select(attributeSelector.selectAllAttributes), this.store.select(searchSelector.selectCriteriaListByRoute), + this.store.select(coneSearchSelector.selectConeSearchByRoute), this.store.select(searchSelector.selectOutputListByRoute) ]), - mergeMap(([action, attributeList, criteriaList, outputList]) => { + mergeMap(([action, pristine, currentDataset, attributeList, criteriaList, coneSearch, outputList]) => { + if (!pristine || !currentDataset) { + // Default form parameters already loaded or no dataset selected + return of({ type: '[No Action] Load Default Form Parameters' }); + } + // Update criteria list let defaultCriteriaList = []; if (criteriaList) { @@ -109,6 +119,17 @@ export class SearchEffects { .map(attribute => stringToCriterion(attribute)); } + // Update cone search + let defaultConeSearch: ConeSearch = null; + if (coneSearch) { + const params = coneSearch.split(':'); + defaultConeSearch = { + ra: +params[0], + dec: +params[1], + radius: +params[2] + }; + } + // Update output list let defaultOutputList = []; if (outputList) { @@ -124,6 +145,7 @@ export class SearchEffects { // Returns actions and mark the form as dirty return [ searchActions.updateCriteriaList({ criteriaList: defaultCriteriaList }), + coneSearchActions.addConeSearch({ coneSearch: defaultConeSearch }), searchActions.updateOutputList({ outputList: defaultOutputList }), searchActions.markAsDirty() ]; @@ -136,13 +158,17 @@ export class SearchEffects { ofType(searchActions.retrieveDataLength), concatLatestFrom(() => [ this.store.select(datasetSelector.selectDatasetNameByRoute), - this.store.select(searchSelector.selectCriteriaList) + this.store.select(searchSelector.selectCriteriaList), + this.store.select(coneSearchSelector.selectConeSearch) ]), - mergeMap(([action, datasetName, criteriaList]) => { + mergeMap(([action, datasetName, criteriaList, coneSearch]) => { let query = datasetName + '?a=count'; if (criteriaList.length > 0) { query += '&c=' + criteriaList.map(criterion => criterionToString(criterion)).join(';'); } + if (coneSearch) { + query += '&cs=' + coneSearch.ra + ':' + coneSearch.dec + ':' + coneSearch.radius; + } return this.searchService.retrieveDataLength(query) .pipe( @@ -166,13 +192,18 @@ export class SearchEffects { concatLatestFrom(() => [ this.store.select(datasetSelector.selectDatasetNameByRoute), this.store.select(searchSelector.selectCriteriaList), + this.store.select(coneSearchSelector.selectConeSearch), this.store.select(searchSelector.selectOutputList) ]), - mergeMap(([action, datasetName, criteriaList, outputList]) => { + mergeMap(([action, datasetName, criteriaList, coneSearch, outputList]) => { let query = datasetName + '?a=' + outputList.join(';'); if (criteriaList.length > 0) { query += '&c=' + criteriaList.map(criterion => criterionToString(criterion)).join(';'); } + if (coneSearch) { + query += '&cs=' + coneSearch.ra + ':' + coneSearch.dec + ':' + coneSearch.radius; + } + query += '&p=' + action.pagination.nbItems + ':' + action.pagination.page; query += '&o=' + action.pagination.sortedCol + ':' + action.pagination.order; diff --git a/client/src/app/instance/store/selectors/cone-search.selector.ts b/client/src/app/instance/store/selectors/cone-search.selector.ts index 3a490d9a..695bba18 100644 --- a/client/src/app/instance/store/selectors/cone-search.selector.ts +++ b/client/src/app/instance/store/selectors/cone-search.selector.ts @@ -36,3 +36,8 @@ export const selectResolverIsLoaded = createSelector( selectConeSearchState, fromConeSearch.selectResolverIsLoaded ); + +export const selectConeSearchByRoute = createSelector( + reducer.selectRouterState, + router => router.state.queryParams.cs as string +); diff --git a/client/src/app/instance/store/selectors/search.selector.ts b/client/src/app/instance/store/selectors/search.selector.ts index ee70032c..094c3673 100644 --- a/client/src/app/instance/store/selectors/search.selector.ts +++ b/client/src/app/instance/store/selectors/search.selector.ts @@ -9,9 +9,10 @@ import { createSelector } from '@ngrx/store'; -import { Criterion, SearchQueryParams, criterionToString } from '../models'; +import { Criterion, SearchQueryParams, criterionToString, ConeSearch } from '../models'; import * as reducer from '../../instance.reducer'; import * as fromSearch from '../reducers/search.reducer'; +import * as coneSearchSelector from './cone-search.selector'; export const selectInstanceState = createSelector( reducer.getInstanceState, @@ -100,12 +101,14 @@ export const selectSelectedData = createSelector( export const selectQueryParams = createSelector( selectCriteriaList, + coneSearchSelector.selectConeSearch, selectOutputList, selectCriteriaStepChecked, selectOutputStepChecked, selectResultStepChecked, ( criteriaList: Criterion[], + coneSearch: ConeSearch, outputList: number[], criteriaStepChecked: boolean, outputStepChecked: boolean, @@ -118,6 +121,12 @@ export const selectQueryParams = createSelector( s: step, a: outputList.join(';') }; + if (coneSearch) { + queryParams = { + ...queryParams, + cs: coneSearch.ra + ':' + coneSearch.dec + ':' + coneSearch.radius + }; + } if (criteriaList.length > 0) { queryParams = { ...queryParams, diff --git a/server/src/Search/Query/ConeSearch.php b/server/src/Search/Query/ConeSearch.php index f229f130..4d4cee16 100644 --- a/server/src/Search/Query/ConeSearch.php +++ b/server/src/Search/Query/ConeSearch.php @@ -45,12 +45,12 @@ class ConeSearch extends AbstractQueryPart $radius = floatval($radius); $coneSearchConfig = $dataset->getConfig()['cone_search']; - if ($coneSearchConfig['enabled'] !== true) { + if ($coneSearchConfig['cone_search_enabled'] !== true) { throw SearchQueryException::coneSearchUnavailable(); } - $attributeRa = $this->getAttribute($dataset, $coneSearchConfig['column_ra']); - $attributeDec = $this->getAttribute($dataset, $coneSearchConfig['column_dec']); + $attributeRa = $this->getAttribute($dataset, $coneSearchConfig['cone_search_column_ra']); + $attributeDec = $this->getAttribute($dataset, $coneSearchConfig['cone_search_column_dec']); $columnRa = $dataset->getTableRef() . '.' . $attributeRa->getName(); $columnDec = $dataset->getTableRef() . '.' . $attributeDec->getName(); -- GitLab