diff --git a/client/src/app/admin/instance/dataset/components/attribute/detail/index.ts b/client/src/app/admin/instance/dataset/components/attribute/detail/index.ts index 4db9273e1ec22368184b553c46b2f8f4a5433a02..d1581ea5b138546e26d7eba21a7cd6d624ce1612 100644 --- a/client/src/app/admin/instance/dataset/components/attribute/detail/index.ts +++ b/client/src/app/admin/instance/dataset/components/attribute/detail/index.ts @@ -9,10 +9,8 @@ import { TableDetailComponent } from './table-detail.component'; import { TrDetailComponent } from './tr-detail.component'; -import { detailRenderers } from './renderers'; export const detailComponents = [ TableDetailComponent, - TrDetailComponent, - detailRenderers + TrDetailComponent ]; diff --git a/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/index.ts b/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/index.ts deleted file mode 100644 index 5d88e779669df93b295514cb7302eede2baab9ad..0000000000000000000000000000000000000000 --- a/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * 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 { SpectraGraphRendererComponent } from './spectra-graph-renderer.component'; - -export const detailRenderers = [ - SpectraGraphRendererComponent -]; - -export * from './renderer-detail-form-factory'; - -export const rendererDetailList = [ - { label: 'Image', value: 'img', display: 10 }, - { label: 'Spectra graph', value: 'spectra_graph', display: 20 } -]; diff --git a/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/renderer-detail-form-factory.ts b/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/renderer-detail-form-factory.ts deleted file mode 100644 index 5108b97da5409e606ea69db631ba93ad80f32454..0000000000000000000000000000000000000000 --- a/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/renderer-detail-form-factory.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * 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 RendererDetailFormFactory { - static create(renderer: string) { - switch (renderer) { - case 'spectra_graph': - return { - z: new FormControl(null) - }; - default: - return {}; - } - } -} diff --git a/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/spectra-graph-renderer.component.html b/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/spectra-graph-renderer.component.html deleted file mode 100644 index 0769a05e96659585e1c99f879f98f9e7256c51c8..0000000000000000000000000000000000000000 --- a/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/spectra-graph-renderer.component.html +++ /dev/null @@ -1,10 +0,0 @@ -<ng-container [formGroup]="form"> - <div class="form-group row align-items-center"> - <label for="{{id}}_z" class="col-md-5 col-sm-12 col-form-label">Attribute z:</label> - <div class="col-md-7 col-sm-12"> - <select class="form-control" name="{{id}}_z" formControlName="z"> - <option *ngFor="let attribute of attributeList" [ngValue]="attribute.id">{{ attribute.form_label }}</option> - </select> - </div> - </div> -</ng-container> \ No newline at end of file diff --git a/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/spectra-graph-renderer.component.ts b/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/spectra-graph-renderer.component.ts deleted file mode 100644 index fa350b065baa875530522459154044c58e830c58..0000000000000000000000000000000000000000 --- a/client/src/app/admin/instance/dataset/components/attribute/detail/renderers/spectra-graph-renderer.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * 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'; - -import { Attribute } from 'src/app/metamodel/models'; - -@Component({ - selector: 'app-spectra-graph-renderer', - templateUrl: 'spectra-graph-renderer.component.html', - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class SpectraGraphRendererComponent { - @Input() id: number; - @Input() form: FormGroup; - @Input() attributeList: Attribute[]; -} diff --git a/client/src/app/admin/instance/dataset/components/attribute/detail/table-detail.component.html b/client/src/app/admin/instance/dataset/components/attribute/detail/table-detail.component.html index b3ee075f0186ae8463790000f23a5d44d651e55a..ae53a43249c09f7380c6d5f6537b6ea13dbaf4bf 100644 --- a/client/src/app/admin/instance/dataset/components/attribute/detail/table-detail.component.html +++ b/client/src/app/admin/instance/dataset/components/attribute/detail/table-detail.component.html @@ -3,10 +3,8 @@ <thead> <tr> <th scope="col" style="min-width:150px">Name</th> - <th scope="col" style="width:50px">Visible</th> - <th scope="col" style="min-width:140px;width:140px;">Display detail</th> - <th scope="col" style="min-width:150px">Renderer</th> - <th scope="col" style="min-width:200px">Renderer config</th> + <th scope="col" style="min-width:150px">Output category</th> + <th scope="col" style="min-width:100px;width:100px;">Display</th> <th scope="col" style="width:50px">Save</th> </tr> </thead> diff --git a/client/src/app/admin/instance/dataset/components/attribute/detail/tr-detail.component.html b/client/src/app/admin/instance/dataset/components/attribute/detail/tr-detail.component.html index 9cf9a69b1fcd8c9d1c97a8292dbc552eacd61cd9..ecb4ec71877ba64a3137d3bd0bcdc813d8c680b0 100644 --- a/client/src/app/admin/instance/dataset/components/attribute/detail/tr-detail.component.html +++ b/client/src/app/admin/instance/dataset/components/attribute/detail/tr-detail.component.html @@ -3,25 +3,13 @@ <input type="text" class="form-control" name="name" formControlName="name"> </td> <td> - <input type="checkbox" class="form-control" name="detail" formControlName="detail"> - </td> - <td> - <input *ngIf="form.controls.detail.value" type="number" class="form-control" name="display_detail" (change)="rendererDetailOnChange()" formControlName="display_detail"> - </td> - <td> - <select *ngIf="form.controls.detail.value" class="form-control" name="renderer_detail" formControlName="renderer_detail"> - <option></option> - <option *ngFor="let rendererDetail of rendererDetailList" [ngValue]="rendererDetail.value">{{ rendererDetail.label }}</option> + <select class="form-control" name="id_detail_output_category" (change)="detailOutputCategoryOnChange()" formControlName="id_detail_output_category"> + <option value=""></option> + <option *ngFor="let category of outputCategoryList" [ngValue]="category.id">{{category.label}}</option> </select> </td> <td> - <ng-container *ngIf="form.controls.renderer_detail.value" [ngSwitch]="form.controls.renderer_detail.value"> - <app-spectra-graph-renderer *ngSwitchCase="'spectra_graph'" - [id]="attribute.id" - [form]="getRendererDetailConfigForm()" - [attributeList]="attributeList"> - </app-spectra-graph-renderer> - </ng-container> + <input *ngIf="form.controls.id_detail_output_category.value" type="number" class="form-control" name="detail_display" formControlName="detail_display"> </td> <td class="text-center align-middle"> <button (click)="submit()" [disabled]="form.invalid || form.pristine" class="btn btn-outline-primary"> diff --git a/client/src/app/admin/instance/dataset/components/attribute/detail/tr-detail.component.ts b/client/src/app/admin/instance/dataset/components/attribute/detail/tr-detail.component.ts index c9f2246ff43a3effc112e53e23d869d15db9025d..d8e82e1779660878b2abbcb775a4e36924daa10d 100644 --- a/client/src/app/admin/instance/dataset/components/attribute/detail/tr-detail.component.ts +++ b/client/src/app/admin/instance/dataset/components/attribute/detail/tr-detail.component.ts @@ -10,8 +10,7 @@ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; -import { Attribute } from 'src/app/metamodel/models'; -import { RendererDetailFormFactory, rendererDetailList } from './renderers'; +import { Attribute, OutputCategory } from 'src/app/metamodel/models'; @Component({ selector: '[detail]', @@ -21,36 +20,24 @@ import { RendererDetailFormFactory, rendererDetailList } from './renderers'; }) export class TrDetailComponent implements OnInit { @Input() attribute: Attribute - @Input() attributeList: Attribute[]; + @Input() outputCategoryList: OutputCategory[]; @Output() save: EventEmitter<Attribute> = new EventEmitter(); - rendererDetailList = rendererDetailList; - public form = new FormGroup({ name: new FormControl({ value: '', disabled: true }), - detail: new FormControl(), - renderer_detail: new FormControl(), - display_detail: new FormControl() + id_detail_output_category: new FormControl(), + detail_display: new FormControl() }); ngOnInit() { if (this.attribute) { - const rendererDetailConfigForm = RendererDetailFormFactory.create(this.attribute.renderer_detail); - this.form.addControl('renderer_detail_config', new FormGroup(rendererDetailConfigForm)); this.form.patchValue(this.attribute); } } - getRendererDetailConfigForm() { - return this.form.controls['renderer_detail_config'] as FormGroup; - } - - rendererDetailOnChange() { - if (this.form.controls.renderer_detail.value === '') { - this.form.controls.renderer_detail.setValue(null); - this.form.setControl('renderer_detail_config', new FormGroup({})); - } else { - this.form.setControl('renderer_detail_config', new FormGroup(RendererDetailFormFactory.create(this.form.controls.renderer_detail.value))); + detailOutputCategoryOnChange(): void { + if (this.form.controls.id.value === '') { + this.form.controls.id_detail_output_category.setValue(null); } } diff --git a/client/src/app/admin/instance/dataset/components/attribute/general/add-attribute.component.ts b/client/src/app/admin/instance/dataset/components/attribute/general/add-attribute.component.ts index c9e6986bd336d361006512e8deea53fc7b213c82..c1f4241c0dd4a8f7130aa5dd27166ab2fa35a3a2 100644 --- a/client/src/app/admin/instance/dataset/components/attribute/general/add-attribute.component.ts +++ b/client/src/app/admin/instance/dataset/components/attribute/general/add-attribute.component.ts @@ -69,10 +69,7 @@ export class AddAttributeComponent { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: id * 10, - renderer_detail: null, - renderer_detail_config: null, + detail_display: id * 10, options: null, vo_utype: null, vo_ucd: null, @@ -81,7 +78,8 @@ export class AddAttributeComponent { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }) } } diff --git a/client/src/app/admin/instance/dataset/components/attribute/result/renderers/detail-link-renderer.component.html b/client/src/app/admin/instance/dataset/components/attribute/result/renderers/detail-link-renderer.component.html index a2f24533af1fd2bed4f66f9acae993525049df9b..aa36946e1b8201cb61c123451d367bd39cebf838 100644 --- a/client/src/app/admin/instance/dataset/components/attribute/result/renderers/detail-link-renderer.component.html +++ b/client/src/app/admin/instance/dataset/components/attribute/result/renderers/detail-link-renderer.component.html @@ -9,14 +9,4 @@ </select> </div> </div> - <div class="form-group row"> - <label for="{{id}}_component" class="col-md-5 col-sm-12 col-form-label">Component:</label> - <div class="col-md-7 col-sm-12"> - <select class="form-control" name="{{id}}_component" formControlName="component"> - <option></option> - <option value="default">Default</option> - <option value="spectra">Spectra</option> - </select> - </div> - </div> </ng-container> diff --git a/client/src/app/admin/instance/dataset/components/attribute/result/renderers/renderer-form-factory.ts b/client/src/app/admin/instance/dataset/components/attribute/result/renderers/renderer-form-factory.ts index a4324fecf84bb41a833870393e7a3784f038fde5..27374e39be6600755a91ee067b84d34141d1f5d1 100644 --- a/client/src/app/admin/instance/dataset/components/attribute/result/renderers/renderer-form-factory.ts +++ b/client/src/app/admin/instance/dataset/components/attribute/result/renderers/renderer-form-factory.ts @@ -14,8 +14,7 @@ export abstract class RendererFormFactory { switch (renderer) { case 'detail-link': return { - display: new FormControl('text'), - component: new FormControl('default') + display: new FormControl('text') }; case 'link': return { diff --git a/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.html b/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.html new file mode 100644 index 0000000000000000000000000000000000000000..d27924f7b1316cc8a0f8f705255f46c8a7d73f72 --- /dev/null +++ b/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.html @@ -0,0 +1,10 @@ +<form [formGroup]="form" (ngSubmit)="submit()" novalidate> + <div class="custom-control custom-switch"> + <input class="custom-control-input" type="checkbox" id="enabled" name="enabled" formControlName="enabled"> + <label class="custom-control-label" for="enabled">Enabled</label> + </div> + <app-webpage-form-content [form]="form" [controlName]="'content'" [controlLabel]="'Content'"></app-webpage-form-content> + <div class="form-group mt-3"> + <ng-content></ng-content> + </div> +</form> diff --git a/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.ts b/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..a0b257653e8489688f7067296111dfb82fd2702d --- /dev/null +++ b/client/src/app/admin/instance/dataset/components/detail-page/detail-config-form.component.ts @@ -0,0 +1,39 @@ +/** + * 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, OnInit, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'; +import { FormGroup, FormControl } from '@angular/forms'; + +import { Attribute, DetailConfig } from 'src/app/metamodel/models'; + +@Component({ + selector: 'app-detail-config-form', + templateUrl: 'detail-config-form.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DetailConfigFormComponent implements OnInit { + @Input() detailConfig: DetailConfig; + @Output() onSubmit: EventEmitter<DetailConfig> = new EventEmitter(); + + public form = new FormGroup({ + enabled: new FormControl(false), + content: new FormControl() + }); + + ngOnInit() { + this.form.patchValue(this.detailConfig); + } + + submit() { + this.onSubmit.emit({ + ...this.form.getRawValue() + }); + this.form.markAsPristine(); + } +} diff --git a/client/src/app/admin/instance/dataset/components/detail-page/detail-config.component.html b/client/src/app/admin/instance/dataset/components/detail-page/detail-config.component.html new file mode 100644 index 0000000000000000000000000000000000000000..57ad9f57db4d0128c7b7f6469cbcdd33610eeb6c --- /dev/null +++ b/client/src/app/admin/instance/dataset/components/detail-page/detail-config.component.html @@ -0,0 +1,8 @@ +<app-detail-config-form + [detailConfig]="detailConfig" + (onSubmit)="save($event)" + #formDetailConfig> + <button [disabled]="!formDetailConfig.form.valid || formDetailConfig.form.pristine" type="submit" class="btn btn-primary"> + <span class="fa fa-database"></span> Save detail config + </button> +</app-detail-config-form> \ No newline at end of file diff --git a/client/src/app/admin/instance/dataset/components/detail-page/detail-config.component.ts b/client/src/app/admin/instance/dataset/components/detail-page/detail-config.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..0d46c4f1a7f131e8442b18454475b3e1daed43eb --- /dev/null +++ b/client/src/app/admin/instance/dataset/components/detail-page/detail-config.component.ts @@ -0,0 +1,34 @@ +/** + * 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 } from '@angular/core'; + +import { DetailConfig } from 'src/app/metamodel/models'; + +@Component({ + selector: 'app-detail-config', + templateUrl: 'detail-config.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DetailConfigComponent { + @Input() detailConfig: DetailConfig; + @Output() addDetailConfig: EventEmitter<DetailConfig> = new EventEmitter(); + @Output() editDetailConfig: EventEmitter<DetailConfig> = new EventEmitter(); + + save(detailConfig: DetailConfig) { + if (this.detailConfig) { + this.editDetailConfig.emit({ + ...this.detailConfig, + ...detailConfig + }); + } else { + this.addDetailConfig.emit(detailConfig); + } + } +} diff --git a/client/src/app/admin/instance/dataset/components/detail-page/index.ts b/client/src/app/admin/instance/dataset/components/detail-page/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..27ce4989d84201ac51a3ac2a01cd652bc16f634d --- /dev/null +++ b/client/src/app/admin/instance/dataset/components/detail-page/index.ts @@ -0,0 +1,7 @@ +import { DetailConfigComponent } from './detail-config.component'; +import { DetailConfigFormComponent } from './detail-config-form.component'; + +export const detailConfigComponents = [ + DetailConfigComponent, + DetailConfigFormComponent +]; diff --git a/client/src/app/admin/instance/dataset/components/index.ts b/client/src/app/admin/instance/dataset/components/index.ts index b28b04af274518cf75b5d4a0ffaf4e3e91654f87..dc81a716e436811b972e13bbf28a8eca3a9ab063 100644 --- a/client/src/app/admin/instance/dataset/components/index.ts +++ b/client/src/app/admin/instance/dataset/components/index.ts @@ -14,6 +14,7 @@ import { datasetFamilyComponents } from './dataset-family'; import { imageComponents } from './image'; import { fileComponents } from './file'; import { coneSearchConfigComponents } from './cone-search-config'; +import { detailConfigComponents } from './detail-page'; import { outputCategoryComponents } from './output-category'; import { outputFamilyComponents } from './output-family'; import { InstanceButtonsComponent } from './instance-buttons.component'; @@ -26,6 +27,7 @@ export const dummiesComponents = [ imageComponents, fileComponents, coneSearchConfigComponents, + detailConfigComponents, outputCategoryComponents, outputFamilyComponents, InstanceButtonsComponent diff --git a/client/src/app/admin/instance/dataset/containers/configure-dataset.component.html b/client/src/app/admin/instance/dataset/containers/configure-dataset.component.html index 48e2723501dc743bce9fd66de2d468043d32068c..bc48f6ba520392a1e1e886e0125b305e847d8eb8 100644 --- a/client/src/app/admin/instance/dataset/containers/configure-dataset.component.html +++ b/client/src/app/admin/instance/dataset/containers/configure-dataset.component.html @@ -4,6 +4,7 @@ || (outputFamilyListIsLoading | async) || (outputCategoryListIsLoading | async) || (imageListIsLoading | async) + || (detailConfigIsLoading | async) || (coneSearchConfigIsLoading | async)"> </app-spinner> @@ -13,6 +14,7 @@ && (outputFamilyListIsLoaded | async) && (outputCategoryListIsLoaded | async) && (imageListIsLoaded | async) + && (detailConfigIsLoaded | async) && (coneSearchConfigIsLoaded | async)" class="container-fluid"> <nav aria-label="breadcrumb"> <ol class="breadcrumb"> @@ -75,6 +77,9 @@ <li class="nav-item"> <a class="nav-link" routerLink="./" [queryParams]="{tab_selected: 'cone-search'}" [ngClass]="{'active': (tabSelected | async) === 'cone-search'}">Cone-search</a> </li> + <li class="nav-item"> + <a class="nav-link" routerLink="./" [queryParams]="{tab_selected: 'detail-page'}" [ngClass]="{'active': (tabSelected | async) === 'detail-page'}">Detail page</a> + </li> </ul> </div> <div class="card-body" [ngSwitch]="tabSelected | async"> @@ -124,7 +129,7 @@ <tr *ngFor="let attribute of (attributeList | async)" detail [attribute]="attribute" - [attributeList]="attributeList | async" + [outputCategoryList]="outputCategoryList | async" (save)="editAttribute($event)"> </tr> </app-table-detail> @@ -195,6 +200,12 @@ (addConeSearchConfig)="addConeSearchConfig($event)" (editConeSearchConfig)="editConeSearchConfig($event)"> </app-cone-search-config> + <app-detail-config + *ngSwitchCase="'detail-page'" + [detailConfig]="detailConfig | async" + (addDetailConfig)="addDetailConfig($event)" + (editDetailConfig)="editDetailConfig($event)"> + </app-detail-config> </div> </div> </div> diff --git a/client/src/app/admin/instance/dataset/containers/configure-dataset.component.ts b/client/src/app/admin/instance/dataset/containers/configure-dataset.component.ts index 51d97035d02561273765a3b1840712e39408b701..d24b7307be2287b1c696328bb840a6e0e8d46a88 100644 --- a/client/src/app/admin/instance/dataset/containers/configure-dataset.component.ts +++ b/client/src/app/admin/instance/dataset/containers/configure-dataset.component.ts @@ -14,7 +14,7 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { Store } from '@ngrx/store'; -import { Instance, Dataset, Attribute, CriteriaFamily, OutputCategory, OutputFamily, Image, File, ConeSearchConfig } from 'src/app/metamodel/models'; +import { Instance, Dataset, Attribute, CriteriaFamily, OutputCategory, OutputFamily, Image, File, ConeSearchConfig, DetailConfig } from 'src/app/metamodel/models'; import { Column, FileInfo, FitsImageLimits } from 'src/app/admin/store/models'; import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector'; import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; @@ -40,6 +40,8 @@ import * as fitsImageActions from 'src/app/admin/store/actions/fits-image.action import * as fitsImageSelector from 'src/app/admin/store/selectors/fits-image.selector'; import * as coneSearchConfigActions from 'src/app/metamodel/actions/cone-search-config.actions'; import * as coneSearchConfigSelector from 'src/app/metamodel/selectors/cone-search-config.selector'; +import * as detailConfigActions from 'src/app/metamodel/actions/detail-config.actions'; +import * as detailConfigSelector from 'src/app/metamodel/selectors/detail-config.selector'; @Component({ selector: 'app-configure-dataset', @@ -85,6 +87,9 @@ export class ConfigureDatasetComponent implements OnInit { public coneSearchConfig: Observable<ConeSearchConfig>; public coneSearchConfigIsLoading: Observable<boolean>; public coneSearchConfigIsLoaded: Observable<boolean>; + public detailConfig: Observable<DetailConfig>; + public detailConfigIsLoading: Observable<boolean>; + public detailConfigIsLoaded: Observable<boolean>; constructor(private store: Store<{ }>, private route: ActivatedRoute) { this.instance = store.select(instanceSelector.selectInstanceByRouteName); @@ -124,6 +129,9 @@ export class ConfigureDatasetComponent implements OnInit { this.coneSearchConfig = store.select(coneSearchConfigSelector.selectConeSearchConfig); this.coneSearchConfigIsLoading = store.select(coneSearchConfigSelector.selectConeSearchConfigIsLoading); this.coneSearchConfigIsLoaded = store.select(coneSearchConfigSelector.selectConeSearchConfigIsLoaded); + this.detailConfig = store.select(detailConfigSelector.selectDetailConfig); + this.detailConfigIsLoading = store.select(detailConfigSelector.selectDetailConfigIsLoading); + this.detailConfigIsLoaded = store.select(detailConfigSelector.selectDetailConfigIsLoaded); } ngOnInit() { @@ -133,6 +141,7 @@ export class ConfigureDatasetComponent implements OnInit { Promise.resolve(null).then(() => this.store.dispatch(outputCategoryActions.loadOutputCategoryList())); Promise.resolve(null).then(() => this.store.dispatch(imageActions.loadImageList())); Promise.resolve(null).then(() => this.store.dispatch(coneSearchConfigActions.loadConeSearchConfig())); + Promise.resolve(null).then(() => this.store.dispatch(detailConfigActions.loadDetailConfig())); this.tabSelected = this.route.queryParamMap.pipe( map(params => params.get('tab_selected')) ); @@ -237,4 +246,12 @@ export class ConfigureDatasetComponent implements OnInit { editConeSearchConfig(coneSearchConfig: ConeSearchConfig) { this.store.dispatch(coneSearchConfigActions.editConeSearchConfig({ coneSearchConfig })); } + + addDetailConfig(detailConfig: DetailConfig) { + this.store.dispatch(detailConfigActions.addDetailConfig({ detailConfig })); + } + + editDetailConfig(detailConfig: DetailConfig) { + this.store.dispatch(detailConfigActions.editDetailConfig({ detailConfig })); + } } diff --git a/client/src/app/admin/instance/webpage/components/webpage-form.component.ts b/client/src/app/admin/instance/webpage/components/webpage-form.component.ts index e473ea5338604cc3fc87b8ee7d71d4e72b99ef58..7c2d4cd833e72b389a8913991ca5ebc5a358e98a 100644 --- a/client/src/app/admin/instance/webpage/components/webpage-form.component.ts +++ b/client/src/app/admin/instance/webpage/components/webpage-form.component.ts @@ -41,11 +41,4 @@ export class WebpageFormComponent implements OnInit { this.onSubmit.emit(this.form.getRawValue()); } } - - getEditorConfig() { - return { - plugins: "lists link image table code help wordcount media", - content_css: "https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" - }; - } } diff --git a/client/src/app/instance/dynamic-content/dynamic-components/index.ts b/client/src/app/instance/dynamic-content/dynamic-components/index.ts deleted file mode 100644 index 81f64b144b7758770edc2f0a2f79810bedc1f3b0..0000000000000000000000000000000000000000 --- a/client/src/app/instance/dynamic-content/dynamic-components/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { DynamicRouterLinkComponent } from './dynamic-router-link.component'; -import { DatasetSampleComponent } from './dataset-sample.component'; - -export const DynamicComponents = [ - DynamicRouterLinkComponent, - DatasetSampleComponent -]; diff --git a/client/src/app/instance/dynamic-content/dynamic-content.module.ts b/client/src/app/instance/dynamic-content/dynamic-content.module.ts deleted file mode 100644 index 8f4f27818c3c0ea4ef559d24a8a79de8f825e191..0000000000000000000000000000000000000000 --- a/client/src/app/instance/dynamic-content/dynamic-content.module.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * 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 { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; - -import { DynamicHooksModule, HookParserEntry } from 'ngx-dynamic-hooks'; - -import { SharedModule } from 'src/app/shared/shared.module'; -import { hookParsers } from './parsers'; -import { DynamicComponents } from './dynamic-components'; -import { dummiesComponents } from './components'; - -export const componentParsers: Array<HookParserEntry> = [ - ...hookParsers, - ...DynamicComponents.map(component => { - return { component }; - }) -]; - -/** - * @class - * @classdesc Dynamic content module. - */ -@NgModule({ - imports: [ - SharedModule, - RouterModule, - DynamicHooksModule.forRoot({ - globalParsers: componentParsers - }), - ], - exports: [ - DynamicHooksModule - ], - providers: [ - hookParsers - ], - declarations: [ - DynamicComponents, - dummiesComponents - ], - entryComponents: [ - DynamicComponents - ] -}) -export class DynamicContentModule { } diff --git a/client/src/app/instance/search/components/criteria/criteria-by-family.component.spec.ts b/client/src/app/instance/search/components/criteria/criteria-by-family.component.spec.ts index 6bcf967ca0b37f1df5418240da083483200cf17b..ec52326679ba7ec5580710e9e52959627a5f8048 100644 --- a/client/src/app/instance/search/components/criteria/criteria-by-family.component.spec.ts +++ b/client/src/app/instance/search/components/criteria/criteria-by-family.component.spec.ts @@ -187,10 +187,7 @@ describe('[Instance][Search][Component][Criteria] CriteriaByFamilyComponent', () renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -203,7 +200,8 @@ describe('[Instance][Search][Component][Criteria] CriteriaByFamilyComponent', () vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null } ]; const attributeId = 1; diff --git a/client/src/app/instance/search/components/detail/default-object.component.html b/client/src/app/instance/search/components/detail/default-object.component.html deleted file mode 100644 index bc6843ae7d94023d1cd8b39b9c9c57631d17822f..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/default-object.component.html +++ /dev/null @@ -1,11 +0,0 @@ -<div class="row justify-content-center"> - <div class="col col-lg-10 col-xl-8 mt-4"> - <app-object-data - [datasetSelected]="datasetSelected" - [outputFamilyList]="outputFamilyList" - [outputCategoryList]="outputCategoryList" - [attributeList]="attributeList" - [object]="object"> - </app-object-data> - </div> -</div> diff --git a/client/src/app/instance/search/components/detail/default-object.component.spec.ts b/client/src/app/instance/search/components/detail/default-object.component.spec.ts deleted file mode 100644 index 24698efed39c3aa1726a35003d06811c4100fe2f..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/default-object.component.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { Component, Input } from '@angular/core'; - -import { DefaultObjectComponent } from './default-object.component'; -import { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models'; - -describe('[Instance][Search][Component][Detail][Default] DefaultObjectComponent', () => { - @Component({ selector: 'app-object-data', template: '' }) - class ObjectDataStubComponent { - @Input() datasetSelected: string; - @Input() outputFamilyList: OutputFamily[]; - @Input() outputCategoryList: OutputCategory[]; - @Input() attributeList: Attribute[]; - @Input() object: any; - } - - let component: DefaultObjectComponent; - let fixture: ComponentFixture<DefaultObjectComponent>; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ - DefaultObjectComponent, - ObjectDataStubComponent - ] - }); - fixture = TestBed.createComponent(DefaultObjectComponent); - component = fixture.componentInstance; - })); - - it('should create the component', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/client/src/app/instance/search/components/detail/default-object.component.ts b/client/src/app/instance/search/components/detail/default-object.component.ts deleted file mode 100644 index b690b814ea75139b70aeb8457d44e465ebdd063c..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/default-object.component.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * 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 { Attribute, OutputFamily, OutputCategory } from 'src/app/metamodel/models'; - -/** - * @class - * @classdesc Detail default object component. - */ -@Component({ - selector: 'app-default-object', - templateUrl: 'default-object.component.html', - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class DefaultObjectComponent { - @Input() datasetSelected: string; - @Input() outputFamilyList: OutputFamily[]; - @Input() outputCategoryList: OutputCategory[]; - @Input() attributeList: Attribute[]; - @Input() object: any; -} diff --git a/client/src/app/instance/search/components/detail/index.ts b/client/src/app/instance/search/components/detail/index.ts deleted file mode 100644 index 86a0c1e9c69b6eec1dd7fcaf5564e0f907c3ba38..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ObjectDataComponent } from './object-data.component'; -import { DefaultObjectComponent } from './default-object.component'; -import { spectraComponents } from './spectra'; - -export const detailsComponents = [ - ObjectDataComponent, - DefaultObjectComponent, - spectraComponents -]; diff --git a/client/src/app/instance/search/components/detail/object-data.component.html b/client/src/app/instance/search/components/detail/object-data.component.html deleted file mode 100644 index 6715883945caaabe47b4e59b39d05e6cf014deea..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/object-data.component.html +++ /dev/null @@ -1,66 +0,0 @@ -<div *ngIf="getAttributeRa() && getAttributeDec()" class="row"> - <div class="col-12"> - <table class="table mb-1" aria-describedby="Object coordinates"> - <tr> - <th scope="col">Alpha</th> - <th scope="col">Delta</th> - <th scope="col" class="text-center" rowspan="2"><img src="assets/cesam_anis80.png" alt="CeSAM logo" /></th> - </tr> - <tr> - <td>{{ object[getAttributeRa().label] }}</td> - <td>{{ object[getAttributeDec().label] }}</td> - </tr> - </table> - <hr class="mt-0 mb-4"> - </div> -</div> - -<!-- Accordion families --> -<accordion [isAnimated]="true"> - <accordion-group *ngFor="let family of outputFamilyList" #ag [isOpen]="true" class="pl-2"> - <button class="btn btn-link btn-block clearfix pb-2" accordion-heading> - <span class="pull-left float-left text-primary"> - {{ family.label }} - - <span *ngIf="ag.isOpen"> - <span class="fas fa-chevron-up"></span> - </span> - <span *ngIf="!ag.isOpen"> - <span class="fas fa-chevron-down"></span> - </span> - </span> - </button> - - <!-- Accordion categories --> - <accordion [isAnimated]="true"> - <accordion-group *ngFor="let category of getCategoryByFamily(family.id)" #ag [isOpen]="true" class="pl-4"> - <button class="btn btn-link btn-block clearfix pb-2" accordion-heading> - <span class="pull-left float-left text-primary"> - {{ category.label }} - - <span *ngIf="ag.isOpen"> - <span class="fas fa-chevron-up"></span> - </span> - <span *ngIf="!ag.isOpen"> - <span class="fas fa-chevron-down"></span> - </span> - </span> - </button> - - <!-- Output list --> - <div *ngFor="let attribute of getAttributesVisibleByCategory(category.id)" class="row pb-2"> - <div class="col-5 font-weight-bold">{{ attribute.form_label }}</div> - <ng-container [ngSwitch]="attribute.renderer_detail"> - <div *ngSwitchCase="'download'" class="col"> - <a [href]="getDownloadHref(object[attribute.label])" role="button" class="btn btn-primary btn-sm"> - <span class="fas fa-download"></span> - {{ object[attribute.label] }} - </a> - </div> - <div *ngSwitchDefault class="col">{{ object[attribute.label] }}</div> - </ng-container > - </div> - </accordion-group> - </accordion> - </accordion-group> -</accordion> diff --git a/client/src/app/instance/search/components/detail/object-data.component.spec.ts b/client/src/app/instance/search/components/detail/object-data.component.spec.ts deleted file mode 100644 index cdc9ba295ddcb75021fd693e230c9a04b7275d0d..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/object-data.component.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; - -import { AccordionModule } from 'ngx-bootstrap/accordion'; - -import { ObjectDataComponent } from './object-data.component'; -import { AppConfigService } from '../../../../app-config.service'; -import { ATTRIBUTE_LIST, CATEGORY_LIST } from '../../../../../test-data'; - -describe('[Instance][Search][Component][Detail] ObjectDataComponent', () => { - let component: ObjectDataComponent; - let fixture: ComponentFixture<ObjectDataComponent>; - let appConfigServiceStub = new AppConfigService(); - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ObjectDataComponent], - imports: [AccordionModule.forRoot()], - providers: [{ provide: AppConfigService, useValue: appConfigServiceStub }] - }); - fixture = TestBed.createComponent(ObjectDataComponent); - component = fixture.componentInstance; - })); - - it('should create the component', () => { - expect(component).toBeTruthy(); - }); - - it('#getCategoryByFamily() should return categories for the given family', () => { - component.outputCategoryList = CATEGORY_LIST; - expect(component.getCategoryByFamily(1).length).toEqual(2); - }); - - it('#getAttributesVisibleByCategory() should return visible attributes for the given category', () => { - component.attributeList = ATTRIBUTE_LIST; - expect(component.getAttributesVisibleByCategory(1).length).toEqual(1); - expect(component.getAttributesVisibleByCategory(1)[0].id).toEqual(2); - }); - - it('#getAttributesVisible() should return visible attributes', () => { - component.attributeList = ATTRIBUTE_LIST; - expect(component.getAttributesVisible().length).toEqual(2); - }); - - it('#getDownloadHref() should return URL', () => { - appConfigServiceStub.apiUrl = 'http://test.com'; - component.datasetSelected = 'myDataset'; - expect(component.getDownloadHref('myAttributeLabel')).toEqual('http://test.com/download-file/myDataset/myAttributeLabel'); - }); -}); diff --git a/client/src/app/instance/search/components/detail/object-data.component.ts b/client/src/app/instance/search/components/detail/object-data.component.ts deleted file mode 100644 index 0b8a4a21ff2045107ec3cf10cdd8e3e7d6a1dd9f..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/object-data.component.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * 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 { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models'; -import { getHost } from 'src/app/shared/utils'; -import { AppConfigService } from 'src/app/app-config.service'; - -/** - * @class - * @classdesc Detail object data component. - */ -@Component({ - selector: 'app-object-data', - templateUrl: 'object-data.component.html', - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class ObjectDataComponent { - @Input() datasetSelected: string; - @Input() outputFamilyList: OutputFamily[]; - @Input() outputCategoryList: OutputCategory[]; - @Input() attributeList: Attribute[]; - @Input() object: any; - - constructor(private appConfig: AppConfigService) { } - - /** - * Returns category list for the given output family ID. - * - * @param {number} idFamily - The output family ID. - * - * @return OutputCategory[] - */ - getCategoryByFamily(idFamily: number): OutputCategory[] { - return this.outputCategoryList - .filter(category => category.id_output_family === idFamily); - } - - /** - * Returns attribute list for the given output category ID that are visible in detail page. - * - * @param {number} idCategory - The output category ID. - * - * @return Attribute[] - */ - getAttributesVisibleByCategory(idCategory: number): Attribute[] { - return this.attributeList - .filter(a => a.detail) - .filter(a => a.id_output_category === idCategory); - } - - /** - * Returns attribute list that are visible in detail page. - * - * @return Attribute[] - */ - getAttributesVisible(): Attribute[] { - return this.attributeList.filter(a => a.detail); - } - - /** - * Returns URL where download object. - * - * @param {string} attributeLabel - The attribute label. - * - * @return string - */ - getDownloadHref(attributeLabel: string): string { - return `${getHost(this.appConfig.apiUrl)}/download-file/${this.datasetSelected}/${attributeLabel}`; - } - - getAttributeRa() { - return this.attributeList.find(attribute => attribute.renderer_detail === 'ra'); - } - - getAttributeDec() { - return this.attributeList.find(attribute => attribute.renderer_detail === 'dec'); - } -} diff --git a/client/src/app/instance/search/components/detail/spectra/index.ts b/client/src/app/instance/search/components/detail/spectra/index.ts deleted file mode 100644 index 77b5e03935e6f4321da07852a1d56a460bc70c3a..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/spectra/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { SpectraObjectComponent } from "./spectra-object.component"; -import { SpectraGraphComponent } from "./graph/spectra-graph.component"; - -export const spectraComponents = [ - SpectraObjectComponent, - SpectraGraphComponent -]; diff --git a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.html b/client/src/app/instance/search/components/detail/spectra/spectra-object.component.html deleted file mode 100644 index 8e1360dc72b1e7d49099e2aa51a59a1ff270e996..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.html +++ /dev/null @@ -1,35 +0,0 @@ -<div class="row"> - <div *ngIf="getAttributeSpectraGraph()" class="col col-md-8 col-sm-12"> - <div *ngIf="spectraIsLoading" id="div-spinner" class="text-center"> - <span class="fas fa-circle-notch fa-spin fa-3x"></span> - <span class="sr-only">Loading...</span> - </div> - <app-spectra-graph *ngIf="spectraIsLoaded" [z]="getZ()" [spectraCSV]="spectraCSV"></app-spectra-graph> - </div> - - <div [ngClass]="{'col-md-4 col-sm-12': getAttributeSpectraGraph()}" class="col mt-4"> - <div *ngIf="getSpectra()" class="jumbotron row mb-3 p-4"> - <div class="col-auto align-self-center"> - <p>Download:</p> - </div> - <div class="w-100 d-block d-xl-none"></div> - <div class="col"> - <div class="row justify-content-center"> - <div class="col-auto"> - <a [href]="getSpectra()" class="btn btn-lg btn-block dl-btn"> - Download SPECTRA archive - </a> - </div> - </div> - </div> - </div> - - <app-object-data - [datasetSelected]="datasetSelected" - [outputFamilyList]="outputFamilyList" - [outputCategoryList]="outputCategoryList" - [attributeList]="attributeList" - [object]="object"> - </app-object-data> - </div> -</div> diff --git a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.scss b/client/src/app/instance/search/components/detail/spectra/spectra-object.component.scss deleted file mode 100644 index 260a2036246abdb58c05276b1a262e50360ac3f3..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.scss +++ /dev/null @@ -1,13 +0,0 @@ -/** - * 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. - */ - -.dl-btn { - height: 80px; - display: inline-block; -} diff --git a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.spec.ts b/client/src/app/instance/search/components/detail/spectra/spectra-object.component.spec.ts deleted file mode 100644 index 890caacf18ba43e6417ac904bdcb27099628aba1..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { Component, Input } from '@angular/core'; - -import { SpectraObjectComponent } from './spectra-object.component'; -import { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models'; -import { AppConfigService } from 'src/app/app-config.service'; -import { ATTRIBUTE_LIST, OBJECT_DETAIL } from 'src/test-data'; - -describe('[Instance][Search][Component][Detail][Spectra] SpectraObjectComponent', () => { - @Component({ selector: 'app-spectra-graph', template: '' }) - class SpectraGraphStubComponent { - @Input() z: number; - @Input() spectraCSV: string; - } - - @Component({ selector: 'app-object-data', template: '' }) - class ObjectDataStubComponent { - @Input() datasetSelected: string; - @Input() outputFamilyList: OutputFamily[]; - @Input() outputCategoryList: OutputCategory[]; - @Input() attributeList: Attribute[]; - @Input() object: any; - } - - let component: SpectraObjectComponent; - let fixture: ComponentFixture<SpectraObjectComponent>; - let appConfigServiceStub = new AppConfigService(); - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ - SpectraObjectComponent, - SpectraGraphStubComponent, - ObjectDataStubComponent - ], - providers: [{ provide: AppConfigService, useValue: appConfigServiceStub }] - }); - fixture = TestBed.createComponent(SpectraObjectComponent); - component = fixture.componentInstance; - }); - - it('should create the component', () => { - expect(component).toBeTruthy(); - }); - - it('#ngOnInit() should emit getSpectraCSV event if an attribute have spectra_graph renderer_detail', () => { - component.attributeList = ATTRIBUTE_LIST; - component.object = OBJECT_DETAIL; - component.getSpectraCSV.subscribe((event: string) => expect(event).toEqual('spec1d')); - component.ngOnInit(); - }); -}); diff --git a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.ts b/client/src/app/instance/search/components/detail/spectra/spectra-object.component.ts deleted file mode 100644 index 97aacb376ba9676c9f0252a7fd6f6acf3a5956f1..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/components/detail/spectra/spectra-object.component.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * 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, Output, EventEmitter, OnInit } from '@angular/core'; - -import { Attribute, OutputCategory, OutputFamily, SpectraGraphRendererConfig } from 'src/app/metamodel/models'; -import { getHost } from 'src/app/shared/utils'; -import { AppConfigService } from 'src/app/app-config.service'; - -/** - * @class - * @classdesc Detail spectra object component. - * - * @implements OnInit - */ -@Component({ - selector: 'app-spectra-object', - templateUrl: 'spectra-object.component.html', - styleUrls: ['spectra-object.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class SpectraObjectComponent implements OnInit { - @Input() datasetSelected: string; - @Input() outputFamilyList: OutputFamily[]; - @Input() outputCategoryList: OutputCategory[]; - @Input() attributeList: Attribute[]; - @Input() object: any; - @Input() spectraIsLoading: boolean; - @Input() spectraIsLoaded: boolean; - @Input() spectraCSV: string; - @Output() getSpectraCSV: EventEmitter<string> = new EventEmitter(); - - constructor(private appConfig: AppConfigService) { } - - ngOnInit(): void { - const attributeSpectraGraph = this.getAttributeSpectraGraph(); - if (attributeSpectraGraph) { - Promise.resolve(null).then(() => this.getSpectraCSV.emit(this.object[attributeSpectraGraph.label])); - } - } - - /** - * Returns spectra file URL. - * - * @return string - */ - getSpectra(): string { - const spectraAttribute = this.attributeList[0]; - return `${getHost(this.appConfig.apiUrl)}/download-file/${this.datasetSelected}/${this.object[spectraAttribute.label]}`; - } - - /** - * Returns detail rendered spectra graph attribute. - * - * @return Attribute - */ - getAttributeSpectraGraph(): Attribute { - return this.attributeList - .filter(a => a.detail) - .find(attribute => attribute.renderer_detail === 'spectra_graph'); - } - - /** - * Returns Z. - * - * @return number - */ - getZ(): number { - const spectraGraphRendererConfig = this.getAttributeSpectraGraph().renderer_detail_config as SpectraGraphRendererConfig; - if (spectraGraphRendererConfig.z) { - const attributeZ = this.attributeList.find(attribute => attribute.id === spectraGraphRendererConfig.z); - return +this.object[attributeZ.label]; - } else { - return 0; - } - } -} diff --git a/client/src/app/instance/search/components/index.ts b/client/src/app/instance/search/components/index.ts index f4057d78828f281aaaf1903fdc286bdd24d240bd..9a0df624bd3563eecf4e0efb3ef5ab367ae7c861 100644 --- a/client/src/app/instance/search/components/index.ts +++ b/client/src/app/instance/search/components/index.ts @@ -4,7 +4,6 @@ import { datasetComponents } from './dataset'; import { criteriaComponents } from './criteria'; import { outputComponents } from './output'; import { resultComponents } from './result'; -import { detailsComponents } from './detail'; export const dummiesComponents = [ ProgressBarComponent, @@ -12,6 +11,5 @@ export const dummiesComponents = [ datasetComponents, criteriaComponents, outputComponents, - resultComponents, - detailsComponents + resultComponents ]; \ No newline at end of file diff --git a/client/src/app/instance/search/components/output/output-by-category.component.spec.ts b/client/src/app/instance/search/components/output/output-by-category.component.spec.ts index 31e0a45f565e90afa4a41ef9d03f65c65acba485..994328f8ea0eede0e5157b32ae82d3444cdb2d05 100644 --- a/client/src/app/instance/search/components/output/output-by-category.component.spec.ts +++ b/client/src/app/instance/search/components/output/output-by-category.component.spec.ts @@ -68,10 +68,7 @@ describe('[Instance][Search][Component][Output] OutputByCategoryComponent', () = renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -80,7 +77,8 @@ describe('[Instance][Search][Component][Output] OutputByCategoryComponent', () = vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }, { id: 1, @@ -104,10 +102,7 @@ describe('[Instance][Search][Component][Output] OutputByCategoryComponent', () = renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: null, vo_utype: null, vo_ucd: null, @@ -116,7 +111,8 @@ describe('[Instance][Search][Component][Output] OutputByCategoryComponent', () = vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null } ]; component.outputList = []; @@ -149,10 +145,7 @@ describe('[Instance][Search][Component][Output] OutputByCategoryComponent', () = renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -161,7 +154,8 @@ describe('[Instance][Search][Component][Output] OutputByCategoryComponent', () = vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }, { id: 1, @@ -185,10 +179,7 @@ describe('[Instance][Search][Component][Output] OutputByCategoryComponent', () = renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: null, vo_utype: null, vo_ucd: null, @@ -197,7 +188,8 @@ describe('[Instance][Search][Component][Output] OutputByCategoryComponent', () = vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null } ]; component.outputList = [1, 2]; diff --git a/client/src/app/instance/search/components/output/output-by-family.component.spec.ts b/client/src/app/instance/search/components/output/output-by-family.component.spec.ts index 1b9d0df47b5c8003ead847e10c9aa1eb0b3f9218..00b112324ce32f4266b172804219afd1e03dd8b8 100644 --- a/client/src/app/instance/search/components/output/output-by-family.component.spec.ts +++ b/client/src/app/instance/search/components/output/output-by-family.component.spec.ts @@ -91,10 +91,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -103,7 +100,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 2 + id_output_category: 2, + id_detail_output_category: null }, { id: 1, @@ -127,10 +125,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: null, vo_utype: null, vo_ucd: null, @@ -139,7 +134,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null } ]; expect(component.getAttributeByCategory(1).length).toBe(1); @@ -170,10 +166,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -182,7 +175,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null }, { id: 1, @@ -206,10 +200,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: null, vo_utype: null, vo_ucd: null, @@ -218,7 +209,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null } ]; component.outputList = [1, 2]; @@ -249,10 +241,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -261,7 +250,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null }, { id: 1, @@ -285,10 +275,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: null, vo_utype: null, vo_ucd: null, @@ -297,7 +284,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null } ]; component.outputList = [1]; @@ -328,10 +316,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -340,7 +325,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null }, { id: 1, @@ -364,10 +350,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: null, vo_utype: null, vo_ucd: null, @@ -376,7 +359,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null } ]; component.outputList = []; @@ -407,10 +391,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -419,7 +400,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null }, { id: 1, @@ -443,10 +425,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: null, vo_utype: null, vo_ucd: null, @@ -455,7 +434,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null } ]; component.outputList = [1]; @@ -486,10 +466,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -498,7 +475,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null }, { id: 1, @@ -522,10 +500,7 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: null, vo_utype: null, vo_ucd: null, @@ -534,7 +509,8 @@ describe('[Instance][Search][Component][Output] OutputByFamilyComponent', () => vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null } ]; const expectedOutputList = [1]; diff --git a/client/src/app/instance/search/components/result/datatable.component.spec.ts b/client/src/app/instance/search/components/result/datatable.component.spec.ts index b10c5be17bdb795885b2b3f837dbcf881f421470..9f07d6c7c3999d222d57a9d3ec752181ddbcc12b 100644 --- a/client/src/app/instance/search/components/result/datatable.component.spec.ts +++ b/client/src/app/instance/search/components/result/datatable.component.spec.ts @@ -133,10 +133,7 @@ describe('[Instance][Search][Component][Result] DatatableComponent', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -145,7 +142,8 @@ describe('[Instance][Search][Component][Result] DatatableComponent', () => { vo_datatype: null, vo_size: null, id_criteria_family: 1, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null }; expect(component.getRendererConfig(attribute)).toBeNull(); const detailLinkRendererConfig: DetailLinkRendererConfig = { diff --git a/client/src/app/instance/search/components/result/renderer/download-renderer.component.spec.ts b/client/src/app/instance/search/components/result/renderer/download-renderer.component.spec.ts index 54e7be5af0a4a0aa2ae76dfcda88a656120cc959..0516b4015abd995f9304ae7962876c5a66a58bd0 100644 --- a/client/src/app/instance/search/components/result/renderer/download-renderer.component.spec.ts +++ b/client/src/app/instance/search/components/result/renderer/download-renderer.component.spec.ts @@ -80,10 +80,7 @@ describe('[Instance][Search][Component][Result][Renderer] DownloadRendererCompon } as DownloadRendererConfig, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -96,7 +93,8 @@ describe('[Instance][Search][Component][Result][Renderer] DownloadRendererCompon vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 2 + id_output_category: 2, + id_detail_output_category: null }; component.attribute = attribute; diff --git a/client/src/app/instance/search/components/result/renderer/image-renderer.component.spec.ts b/client/src/app/instance/search/components/result/renderer/image-renderer.component.spec.ts index e240308ad06a85de0f056744c9b57a5f7277e235..4f833cf3cc525f1bb42becbfc9c91a38eb623b10 100644 --- a/client/src/app/instance/search/components/result/renderer/image-renderer.component.spec.ts +++ b/client/src/app/instance/search/components/result/renderer/image-renderer.component.spec.ts @@ -54,10 +54,7 @@ describe('[Instance][Search][Component][Result][Renderer] ImageRendererComponent } as ImageRendererConfig, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -70,7 +67,8 @@ describe('[Instance][Search][Component][Result][Renderer] ImageRendererComponent vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 2 + id_output_category: 2, + id_detail_output_category: null }; const dataset = { diff --git a/client/src/app/instance/search/components/result/renderer/link-renderer.component.spec.ts b/client/src/app/instance/search/components/result/renderer/link-renderer.component.spec.ts index dcd3aae95c735fcb1a1f80915a8c6045e396cf2d..752d6be14174f9add83bac7486b8be3e7015b801 100644 --- a/client/src/app/instance/search/components/result/renderer/link-renderer.component.spec.ts +++ b/client/src/app/instance/search/components/result/renderer/link-renderer.component.spec.ts @@ -49,10 +49,7 @@ describe('[Instance][Search][Component][Result][Renderer] LinkRendererComponent' } as LinkRendererConfig, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -65,7 +62,8 @@ describe('[Instance][Search][Component][Result][Renderer] LinkRendererComponent' vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 2 + id_output_category: 2, + id_detail_output_category: null }; component.attribute = attribute; @@ -103,10 +101,7 @@ describe('[Instance][Search][Component][Result][Renderer] LinkRendererComponent' } as LinkRendererConfig, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -119,7 +114,8 @@ describe('[Instance][Search][Component][Result][Renderer] LinkRendererComponent' vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 2 + id_output_category: 2, + id_detail_output_category: null }; component.attribute = attribute; diff --git a/client/src/app/instance/search/containers/detail.component.html b/client/src/app/instance/search/containers/detail.component.html deleted file mode 100644 index 3ceca60ed2a736979571553b040484ca49c9861d..0000000000000000000000000000000000000000 --- a/client/src/app/instance/search/containers/detail.component.html +++ /dev/null @@ -1,40 +0,0 @@ -<div class="container-fluid"> - <div *ngIf="!(pristine | async)" class="row mt-2 mb-2 justify-content-between"> - <div class="col"> - <button (click)="goBackToResult()" class="btn btn-outline-secondary"> - <span class="fa fa-backward"></span> Back to search results - </button> - </div> - </div> - <app-spinner *ngIf="(attributeListIsLoading | async) - || (outputFamilyListIsLoading | async) - || (outputCategoryListIsLoading | async) - || (objectIsLoading | async)"> - </app-spinner> - <ng-container *ngIf="(attributeListIsLoaded | async) - && (outputFamilyListIsLoaded | async) - && (outputCategoryListIsLoaded | async) - && (objectIsLoaded | async)" [ngSwitch]="getDetailComponent(attributeList | async)"> - <app-spectra-object *ngSwitchCase="'spectra'" - [datasetSelected]="datasetSelected | async" - [outputFamilyList]="outputFamilyList | async" - [outputCategoryList]="outputCategoryList | async" - [attributeList]="attributeList | async | sortByDetailDisplay" - [object]="object | async" - [spectraCSV]="spectraCSV | async" - [spectraIsLoading]="spectraIsLoading | async" - [spectraIsLoaded]="spectraIsLoaded | async" - (getSpectraCSV)="getSpectraCSV($event)"> - </app-spectra-object> - <app-default-object *ngSwitchCase="'default'" - [datasetSelected]="datasetSelected | async" - [outputFamilyList]="outputFamilyList | async" - [outputCategoryList]="outputCategoryList | async" - [attributeList]="attributeList | async | sortByDetailDisplay" - [object]="object | async"> - </app-default-object> - <div *ngSwitchDefault> - Detail component <span class="font-weight-bold">{{ getDetailComponent(attributeList | async) }}</span> not supported ! - </div> - </ng-container> -</div> diff --git a/client/src/app/instance/search/detail/components/detail-content.component.html b/client/src/app/instance/search/detail/components/detail-content.component.html new file mode 100644 index 0000000000000000000000000000000000000000..b0961d8fb18ce48ec3ba35de925aa73c81ba1435 --- /dev/null +++ b/client/src/app/instance/search/detail/components/detail-content.component.html @@ -0,0 +1,5 @@ +<ngx-dynamic-hooks + [content]="detailConfig.content" + [parsers]="getParsers()" + [context]="getContext()"> +</ngx-dynamic-hooks> diff --git a/client/src/app/instance/search/detail/components/detail-content.component.ts b/client/src/app/instance/search/detail/components/detail-content.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..ca7dfd6084994540ef89324a035ded66e5620c1f --- /dev/null +++ b/client/src/app/instance/search/detail/components/detail-content.component.ts @@ -0,0 +1,49 @@ +/** + * 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 { DetailConfig, Dataset, Attribute, OutputFamily, OutputCategory } from 'src/app/metamodel/models'; +import { globalParsers } from 'src/app/shared/dynamic-content'; +import { componentParsers } from '../dynamic-content'; + +/** + * @class + * @classdesc Detail content component. + */ +@Component({ + selector: 'app-detail-content', + templateUrl: 'detail-content.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DetailContentComponent { + @Input() detailConfig: DetailConfig; + @Input() object: any; + @Input() datasetName: string; + @Input() attributeList: Attribute[]; + @Input() outputFamilyList: OutputFamily[]; + @Input() outputCategoryList: OutputCategory[]; + + getParsers() { + return [ + ...globalParsers, + ...componentParsers + ]; + } + + getContext() { + return { + object: this.object, + datasetName: this.datasetName, + attributeList: this.attributeList, + outputFamilyList: this.outputFamilyList, + outputCategoryList: this.outputCategoryList + }; + } +} diff --git a/client/src/app/instance/dynamic-content/components/index.ts b/client/src/app/instance/search/detail/components/index.ts similarity index 74% rename from client/src/app/instance/dynamic-content/components/index.ts rename to client/src/app/instance/search/detail/components/index.ts index b3594ebb9a4ea93fe6a85fd9f3df57b631d27e0d..0dcbf58e5e5f4fdf19dfc73aac0bc8039807a695 100644 --- a/client/src/app/instance/dynamic-content/components/index.ts +++ b/client/src/app/instance/search/detail/components/index.ts @@ -7,8 +7,8 @@ * file that was distributed with this source code. */ -import { DatatableComponent } from './datatable.component'; +import { DetailContentComponent } from './detail-content.component'; export const dummiesComponents = [ - DatatableComponent + DetailContentComponent ]; diff --git a/client/src/app/instance/search/detail/containers/detail.component.html b/client/src/app/instance/search/detail/containers/detail.component.html new file mode 100644 index 0000000000000000000000000000000000000000..9c0a7eb8e8cc8c977e3eb39e08d854bb28642503 --- /dev/null +++ b/client/src/app/instance/search/detail/containers/detail.component.html @@ -0,0 +1,29 @@ +<div class="container-fluid"> + <div *ngIf="!(pristine | async)" class="row mt-2 mb-2 justify-content-between"> + <div class="col"> + <a routerLink="/instance/{{ instanceSelected | async }}/search/result/{{ datasetSelected | async }}" [queryParams]="queryParams | async" class="btn btn-outline-secondary"> + <span class="fa fa-backward"></span> Back to search results + </a> + </div> + </div> + <app-spinner *ngIf="(detailConfigIsLoading | async) + || (attributeListIsLoading | async) + || (outputFamilyListIsLoading | async) + || (outputCategoryListIsLoading | async) + || (objectIsLoading | async)"> + </app-spinner> + <ng-container *ngIf="(detailConfigIsLoaded | async) + && (attributeListIsLoaded | async) + && (outputFamilyListIsLoaded | async) + && (outputCategoryListIsLoaded | async) + && (objectIsLoaded | async)"> + <app-detail-content + [detailConfig]="detailConfig | async" + [object]="object | async" + [datasetName]="datasetSelected | async" + [attributeList]="attributeList | async" + [outputFamilyList]="outputFamilyList | async" + [outputCategoryList]="outputCategoryList | async"> + </app-detail-content> + </ng-container> +</div> diff --git a/client/src/app/instance/search/containers/detail.component.spec.ts b/client/src/app/instance/search/detail/containers/detail.component.spec.ts similarity index 53% rename from client/src/app/instance/search/containers/detail.component.spec.ts rename to client/src/app/instance/search/detail/containers/detail.component.spec.ts index eabd6e35c007e264f019a083d8b618dbe86916da..acfea7bc7bd8a71a33c6a72469aa17ab001ecdeb 100644 --- a/client/src/app/instance/search/containers/detail.component.spec.ts +++ b/client/src/app/instance/search/detail/containers/detail.component.spec.ts @@ -1,59 +1,43 @@ import { Component, InjectionToken, Input } from '@angular/core'; -import { ComponentFixture, TestBed, inject, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { Location } from '@angular/common'; import { provideMockStore, MockStore } from '@ngrx/store/testing'; import { of } from 'rxjs'; import { DetailComponent } from './detail.component'; -import { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models'; -import { SortByDetailDisplay } from '../pipes/sort-by-detail-display'; -import { ATTRIBUTE_LIST } from 'src/test-data'; +import { Attribute, DetailConfig, OutputCategory, OutputFamily } from 'src/app/metamodel/models'; import * as detailActions from 'src/app/instance/store/actions/detail.actions'; +import * as detailConfigActions from 'src/app/metamodel/actions/detail-config.actions'; import * as searchActions from 'src/app/instance/store/actions/search.actions'; describe('[Instance][Search][Container] DetailComponent', () => { @Component({ selector: 'app-spinner', template: '' }) class SpinnerStubComponent { } - @Component({ selector: 'app-spectra-object', template: '' }) - class SpectraObjectStubComponent { - @Input() datasetSelected: string; - @Input() outputFamilyList: OutputFamily[]; - @Input() outputCategoryList: OutputCategory[]; - @Input() attributeList: Attribute[]; + @Component({ selector: 'app-detail-content ', template: '' }) + class DetailContentStubComponent { + @Input() detailConfig: DetailConfig @Input() object: any; - @Input() spectraIsLoading: boolean; - @Input() spectraIsLoaded: boolean; - @Input() spectraCSV: string; - } - - @Component({ selector: 'app-default-object', template: '' }) - class DefaultObjectStubComponent { - @Input() datasetSelected: string; + @Input() datasetName: string; + @Input() attributeList: Attribute[]; @Input() outputFamilyList: OutputFamily[]; @Input() outputCategoryList: OutputCategory[]; - @Input() attributeList: Attribute[]; - @Input() object: any; } let component: DetailComponent; let fixture: ComponentFixture<DetailComponent>; let store: MockStore; - const LOCATION_TOKEN = new InjectionToken<Location>('Window location object'); beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ declarations: [ DetailComponent, SpinnerStubComponent, - SpectraObjectStubComponent, - DefaultObjectStubComponent, - SortByDetailDisplay + DetailContentStubComponent ], providers: [ - provideMockStore({ }), - { provide: LOCATION_TOKEN, useValue: window.history } + provideMockStore({ }) ] }); fixture = TestBed.createComponent(DetailComponent); @@ -70,28 +54,15 @@ describe('[Instance][Search][Container] DetailComponent', () => { const spy = jest.spyOn(store, 'dispatch'); component.ngOnInit(); Promise.resolve(null).then(function() { - expect(spy).toHaveBeenCalledTimes(3); + expect(spy).toHaveBeenCalledTimes(4); expect(spy).toHaveBeenCalledWith(searchActions.initSearch()); expect(spy).toHaveBeenCalledWith(searchActions.loadDefaultFormParameters()); expect(spy).toHaveBeenCalledWith(detailActions.retrieveObject()); + expect(spy).toHaveBeenCalledWith(detailConfigActions.loadDetailConfig()); done(); }); }); - it ('#goBackToResult() should go to the previous location', inject([LOCATION_TOKEN], (location: Location) => { - jest.spyOn(location, 'back'); - component.goBackToResult(); - expect(location.back).toHaveBeenCalledTimes(1); - })); - - it('#getSpectraCSV() should dispatch RetrieveSpectraAction', () => { - // const retrieveSpectraAction = new detailActions.retrieveSpectra({ filename: 'toto' }); - const spy = jest.spyOn(store, 'dispatch'); - component.getSpectraCSV('toto'); - expect(spy).toHaveBeenCalledTimes(1); - expect(spy).toHaveBeenCalledWith(detailActions.retrieveSpectra({ filename: 'toto' })); - }); - it('#ngOnDestroy() should unsubscribe from attributeListIsLoadedSubscription', () => { component.attributeListIsLoadedSubscription = of().subscribe(); const spy = jest.spyOn(component.attributeListIsLoadedSubscription, 'unsubscribe'); diff --git a/client/src/app/instance/search/containers/detail.component.ts b/client/src/app/instance/search/detail/containers/detail.component.ts similarity index 78% rename from client/src/app/instance/search/containers/detail.component.ts rename to client/src/app/instance/search/detail/containers/detail.component.ts index 78d4b5f69732f88b4fa2cff913292cf63a78dc27..7e354d22926ce2574faebca4e53b688021e022de 100644 --- a/client/src/app/instance/search/containers/detail.component.ts +++ b/client/src/app/instance/search/detail/containers/detail.component.ts @@ -13,15 +13,19 @@ import { Location } from '@angular/common'; import { Store } from '@ngrx/store'; import { Observable, Subscription } from 'rxjs'; -import { Attribute, OutputCategory, OutputFamily, DetailLinkRendererConfig } from 'src/app/metamodel/models'; +import { Attribute, OutputCategory, OutputFamily, DetailConfig } from 'src/app/metamodel/models'; +import { SearchQueryParams } from 'src/app/instance/store/models'; import * as detailActions from 'src/app/instance/store/actions/detail.actions'; import * as detailSelector from 'src/app/instance/store/selectors/detail.selector'; +import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector'; import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; import * as searchSelector from 'src/app/instance/store/selectors/search.selector'; import * as outputFamilySelector from 'src/app/metamodel/selectors/output-family.selector'; import * as outputCategorySelector from 'src/app/metamodel/selectors/output-category.selector'; import * as attributeSelector from 'src/app/metamodel/selectors/attribute.selector'; import * as searchActions from 'src/app/instance/store/actions/search.actions'; +import * as detailConfigActions from 'src/app/metamodel/actions/detail-config.actions'; +import * as detailConfigSelector from 'src/app/metamodel/selectors/detail-config.selector'; /** * @class @@ -35,8 +39,12 @@ import * as searchActions from 'src/app/instance/store/actions/search.actions'; templateUrl: 'detail.component.html' }) export class DetailComponent implements OnInit, OnDestroy { + public instanceSelected: Observable<string>; public datasetSelected: Observable<string>; public pristine: Observable<boolean>; + public detailConfig: Observable<DetailConfig>; + public detailConfigIsLoading: Observable<boolean>; + public detailConfigIsLoaded: Observable<boolean>; public attributeList: Observable<Attribute[]>; public attributeListIsLoading: Observable<boolean>; public attributeListIsLoaded: Observable<boolean>; @@ -49,15 +57,17 @@ export class DetailComponent implements OnInit, OnDestroy { public object: Observable<any>; public objectIsLoading: Observable<boolean>; public objectIsLoaded: Observable<boolean>; - public spectraCSV: Observable<string>; - public spectraIsLoading: Observable<boolean>; - public spectraIsLoaded: Observable<boolean>; + public queryParams: Observable<SearchQueryParams>; public attributeListIsLoadedSubscription: Subscription; constructor(private location: Location, private store: Store<{ }>) { + this.instanceSelected = store.select(instanceSelector.selectInstanceNameByRoute); this.datasetSelected = store.select(datasetSelector.selectDatasetNameByRoute); this.pristine = store.select(searchSelector.selectPristine); + this.detailConfig = store.select(detailConfigSelector.selectDetailConfig); + this.detailConfigIsLoading = store.select(detailConfigSelector.selectDetailConfigIsLoading); + this.detailConfigIsLoaded = store.select(detailConfigSelector.selectDetailConfigIsLoaded); this.attributeList = store.select(attributeSelector.selectAllAttributes); this.attributeListIsLoading = store.select(attributeSelector.selectAttributeListIsLoading); this.attributeListIsLoaded = store.select(attributeSelector.selectAttributeListIsLoaded); @@ -70,9 +80,7 @@ export class DetailComponent implements OnInit, OnDestroy { this.object = this.store.select(detailSelector.selectObject); this.objectIsLoading = this.store.select(detailSelector.selectObjectIsLoading); this.objectIsLoaded = this.store.select(detailSelector.selectObjectIsLoaded); - this.spectraCSV = this.store.select(detailSelector.selectSpectraCSV); - this.spectraIsLoading = this.store.select(detailSelector.selectObjectIsLoading); - this.spectraIsLoaded = this.store.select(detailSelector.selectSpectraIsLoaded); + this.queryParams = this.store.select(searchSelector.selectQueryParams); } ngOnInit(): void { @@ -85,27 +93,7 @@ export class DetailComponent implements OnInit, OnDestroy { Promise.resolve(null).then(() => this.store.dispatch(detailActions.retrieveObject())); } }); - } - - /** - * Gets back to result page. - */ - goBackToResult(): void { - this.location.back(); - } - - getDetailComponent(attributeList: Attribute[]) { - const attribute = attributeList.find(attribute => attribute.renderer === 'detail-link').renderer_config as DetailLinkRendererConfig; - return attribute.component; - } - - /** - * Dispatches action to retrieve spectra file. - * - * @param {string} spectraFile - The spectra file name. - */ - getSpectraCSV(spectraFile: string): void { - this.store.dispatch(detailActions.retrieveSpectra({ filename: spectraFile })); + Promise.resolve(null).then(() => this.store.dispatch(detailConfigActions.loadDetailConfig())); } /** diff --git a/client/src/app/instance/search/detail/detail-routing.module.ts b/client/src/app/instance/search/detail/detail-routing.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b32f4090e5baf2dfedf5abf50f6e8a391be6add --- /dev/null +++ b/client/src/app/instance/search/detail/detail-routing.module.ts @@ -0,0 +1,32 @@ +/** + * 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 { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +import { DetailComponent } from './containers/detail.component'; + +const routes: Routes = [ + { path: '', redirectTo: ':dname/:id', pathMatch: 'full' }, + { path: ':dname/:id', component: DetailComponent } +]; + +/** + * @class + * @classdesc Search routing module. + */ + @NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class DetailRoutingModule { } + +export const routedComponents = [ + DetailComponent +]; diff --git a/client/src/app/instance/search/detail/detail.module.ts b/client/src/app/instance/search/detail/detail.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..f272f91753733e577c6db6d053b75579258ccbda --- /dev/null +++ b/client/src/app/instance/search/detail/detail.module.ts @@ -0,0 +1,38 @@ +/** + * 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 { NgModule } from '@angular/core'; + +import { SharedModule } from 'src/app/shared/shared.module'; +import { DetailRoutingModule, routedComponents } from './detail-routing.module'; +import { dummiesComponents } from './components'; +import { hookParsers, dynamicComponents } from './dynamic-content'; + +/** + * @class + * @classdesc Search module. + */ +@NgModule({ + imports: [ + SharedModule, + DetailRoutingModule + ], + declarations: [ + routedComponents, + dummiesComponents, + dynamicComponents + ], + entryComponents: [ + dynamicComponents + ], + providers: [ + hookParsers + ] +}) +export class DetailModule { } diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-object.component.html b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-object.component.html new file mode 100644 index 0000000000000000000000000000000000000000..5c1adc90c23c6bec1e06f2c4e4499b6319cea7e0 --- /dev/null +++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-object.component.html @@ -0,0 +1,41 @@ +<!-- Accordion families --> +<accordion [isAnimated]="true"> + <accordion-group *ngFor="let family of outputFamilyList" #ag [isOpen]="true" class="pl-2"> + <button class="btn btn-link btn-block clearfix pb-2" accordion-heading> + <span class="pull-left float-left text-primary"> + {{ family.label }} + + <span *ngIf="ag.isOpen"> + <span class="fas fa-chevron-up"></span> + </span> + <span *ngIf="!ag.isOpen"> + <span class="fas fa-chevron-down"></span> + </span> + </span> + </button> + + <!-- Accordion categories --> + <accordion [isAnimated]="true"> + <accordion-group *ngFor="let category of getOutputCategoryListByFamily(family.id)" #ag [isOpen]="true" class="pl-4"> + <button class="btn btn-link btn-block clearfix pb-2" accordion-heading> + <span class="pull-left float-left text-primary"> + {{ category.label }} + + <span *ngIf="ag.isOpen"> + <span class="fas fa-chevron-up"></span> + </span> + <span *ngIf="!ag.isOpen"> + <span class="fas fa-chevron-down"></span> + </span> + </span> + </button> + + <!-- Output list --> + <div *ngFor="let attribute of getAttributeListByOutputCategory(category.id)" class="row pb-2"> + <div class="col-5 font-weight-bold">{{ attribute.form_label }}</div> + <div class="col">{{ object[attribute.label] }}</div> + </div> + </accordion-group> + </accordion> + </accordion-group> +</accordion> \ No newline at end of file diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-object.component.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-object.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c029c11508c6dbce4d80c0a89fb24e29e900430 --- /dev/null +++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-object.component.ts @@ -0,0 +1,36 @@ +/** + * 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 { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models'; + +/** + * @class + * @classdesc Display object component. + */ +@Component({ + selector: 'app-display-object', + templateUrl: 'display-object.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DisplayObjectComponent { + @Input() object: any; + @Input() attributeList: Attribute[]; + @Input() outputFamilyList: OutputFamily[]; + @Input() outputCategoryList: OutputCategory[]; + + getOutputCategoryListByFamily(idOutputFamily: number): OutputCategory[] { + return this.outputCategoryList.filter(outputCategory => outputCategory.id_output_family === idOutputFamily); + } + + getAttributeListByOutputCategory(idOutputCategory: number): Attribute[] { + return this.attributeList.filter(attribute => attribute.id_detail_output_category === idOutputCategory); + } +} diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.html b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.html new file mode 100644 index 0000000000000000000000000000000000000000..b779cc47211c89b6f36fd14b0fd435e532d3ec9d --- /dev/null +++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.html @@ -0,0 +1,11 @@ +<table class="table mb-1" aria-describedby="Object coordinates"> + <tr> + <th scope="col">Alpha</th> + <th scope="col">Delta</th> + <th scope="col" class="text-center" rowspan="2"><img src="assets/cesam_anis80.png" alt="CeSAM logo" /></th> + </tr> + <tr> + <td>{{ object[getAttributeRa().label] }}</td> + <td>{{ object[getAttributeDec().label] }}</td> + </tr> +</table> diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..4715be9b5bc9e0fe6d765d52d4721117b1544da0 --- /dev/null +++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-ra-dec.component.ts @@ -0,0 +1,36 @@ +/** + * 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 { Attribute } from 'src/app/metamodel/models'; + +/** + * @class + * @classdesc Display object component. + */ +@Component({ + selector: 'app-display-ra-dec', + templateUrl: 'display-ra-dec.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DisplayRaDecComponent { + @Input() object: any; + @Input() attributeList: Attribute[]; + @Input() attributeRaId: number; + @Input() attributeDecId: number; + + getAttributeRa() { + return this.attributeList.find(attribute => attribute.id === this.attributeRaId); + } + + getAttributeDec() { + return this.attributeList.find(attribute => attribute.id === this.attributeDecId); + } +} diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.html b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.html new file mode 100644 index 0000000000000000000000000000000000000000..f908a1e04a212c8fe72ca15abc8601591eabbf39 --- /dev/null +++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.html @@ -0,0 +1 @@ +<app-spectra-graph *ngIf="spectraCSV | async as data" [z]="getZ()" [spectraCSV]="data"></app-spectra-graph> diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..fcf7ffedf84bdb92861c0fe467e887250b31f964 --- /dev/null +++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/display-spectra.component.ts @@ -0,0 +1,47 @@ +/** + * 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 { HttpClient } from '@angular/common/http'; + +import { Observable } from 'rxjs'; + +import { Attribute } from 'src/app/metamodel/models'; +import { AppConfigService } from 'src/app/app-config.service'; + +/** + * @class + * @classdesc Display spectra component. + */ +@Component({ + selector: 'app-display-spectra', + templateUrl: 'display-spectra.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DisplaySpectraComponent { + @Input() object: any; + @Input() datasetName: string; + @Input() attributeList: Attribute[]; + @Input() attributeSpectraId: number; + @Input() attributeZId: number; + + spectraCSV: Observable<string>; + + constructor(private http: HttpClient, private config: AppConfigService) { } + + ngOnInit() { + const spectraFile = this.object[this.attributeList.find(attribute => attribute.id === this.attributeSpectraId).label]; + this.spectraCSV = this.http.get(`${this.config.servicesUrl}/spectra-to-csv/${this.datasetName}?filename=${spectraFile}`, { responseType: 'text' }); + } + + getZ() { + const z = this.object[this.attributeList.find(attribute => attribute.id === this.attributeZId).label]; + return +z; + } +} diff --git a/client/src/app/instance/search/detail/dynamic-content/dynamic-components/index.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..8c84be9b710bc658c127711e99eadc76678a664e --- /dev/null +++ b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/index.ts @@ -0,0 +1,11 @@ +import { DisplayObjectComponent } from './display-object.component'; +import { DisplayRaDecComponent } from './display-ra-dec.component'; +import { DisplaySpectraComponent } from './display-spectra.component'; +import { SpectraGraphComponent } from './spectra-graph/spectra-graph.component'; + +export const dynamicComponents = [ + DisplayObjectComponent, + DisplayRaDecComponent, + DisplaySpectraComponent, + SpectraGraphComponent +]; diff --git a/client/src/app/instance/search/components/detail/spectra/graph/point.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/point.ts similarity index 100% rename from client/src/app/instance/search/components/detail/spectra/graph/point.ts rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/point.ts diff --git a/client/src/app/instance/search/components/detail/spectra/graph/rays.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/rays.ts similarity index 100% rename from client/src/app/instance/search/components/detail/spectra/graph/rays.ts rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/rays.ts diff --git a/client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.html b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.html similarity index 100% rename from client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.html rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.html diff --git a/client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.scss b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.scss similarity index 100% rename from client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.scss rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.scss diff --git a/client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.ts similarity index 100% rename from client/src/app/instance/search/components/detail/spectra/graph/spectra-graph.component.ts rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-graph.component.ts diff --git a/client/src/app/instance/search/components/detail/spectra/graph/spectra-type.ts b/client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-type.ts similarity index 100% rename from client/src/app/instance/search/components/detail/spectra/graph/spectra-type.ts rename to client/src/app/instance/search/detail/dynamic-content/dynamic-components/spectra-graph/spectra-type.ts diff --git a/client/src/app/instance/search/detail/dynamic-content/index.ts b/client/src/app/instance/search/detail/dynamic-content/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a8a58f220117ec5118c9ca18d1f0e91af6ee7015 --- /dev/null +++ b/client/src/app/instance/search/detail/dynamic-content/index.ts @@ -0,0 +1,14 @@ +import { HookParserEntry } from 'ngx-dynamic-hooks'; + +import { hookParsers } from './parsers'; +import { dynamicComponents } from './dynamic-components'; + +export const componentParsers: Array<HookParserEntry> = [ + ...hookParsers, + ...dynamicComponents.map(component => { + return { component }; + }) +]; + +export { hookParsers } from './parsers'; +export { dynamicComponents } from './dynamic-components'; diff --git a/client/src/app/instance/search/detail/dynamic-content/parsers/index.ts b/client/src/app/instance/search/detail/dynamic-content/parsers/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..552c5a60f42b85a8d485439c9086f2c80778140f --- /dev/null +++ b/client/src/app/instance/search/detail/dynamic-content/parsers/index.ts @@ -0,0 +1,3 @@ +export const hookParsers = [ + +]; diff --git a/client/src/app/instance/search/pipes/sort-by-criteria-display.pipe.spec.ts b/client/src/app/instance/search/pipes/sort-by-criteria-display.pipe.spec.ts index 4d06e2739ddb3405873b53bfc2313a6d78409dff..7cc6dc72b156e83c834f16e1fc0aa95f3e11816c 100644 --- a/client/src/app/instance/search/pipes/sort-by-criteria-display.pipe.spec.ts +++ b/client/src/app/instance/search/pipes/sort-by-criteria-display.pipe.spec.ts @@ -28,10 +28,7 @@ describe('[Instance][Search][Pipe] SortByCriteriaDisplayPipe', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -40,7 +37,8 @@ describe('[Instance][Search][Pipe] SortByCriteriaDisplayPipe', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }, { id: 1, @@ -64,10 +62,7 @@ describe('[Instance][Search][Pipe] SortByCriteriaDisplayPipe', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: null, vo_utype: null, vo_ucd: null, @@ -76,7 +71,8 @@ describe('[Instance][Search][Pipe] SortByCriteriaDisplayPipe', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null } ]; expect(pipe.transform(attributeList)[0].id).toBe(1); diff --git a/client/src/app/instance/search/pipes/sort-by-detail-display.spec.ts b/client/src/app/instance/search/pipes/sort-by-detail-display.spec.ts index f3cb99f44e266086165f6ae66b121bea401865f5..708cd1f38bb3423de88148397cb74dee1489dce4 100644 --- a/client/src/app/instance/search/pipes/sort-by-detail-display.spec.ts +++ b/client/src/app/instance/search/pipes/sort-by-detail-display.spec.ts @@ -28,10 +28,7 @@ describe('[Instance][Search][Pipe] SortByDetailDisplay', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -44,7 +41,8 @@ describe('[Instance][Search][Pipe] SortByDetailDisplay', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }, { id: 2, @@ -68,10 +66,7 @@ describe('[Instance][Search][Pipe] SortByDetailDisplay', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -85,6 +80,7 @@ describe('[Instance][Search][Pipe] SortByDetailDisplay', () => { vo_size: null, id_criteria_family: null, id_output_category: null, + id_detail_output_category: null } ]; expect(pipe.transform(attributeList)[0].id).toBe(2); diff --git a/client/src/app/instance/search/pipes/sort-by-detail-display.ts b/client/src/app/instance/search/pipes/sort-by-detail-display.ts index dd17a7ca46d072c91e36aa534811d4ae89a2ada4..2887500ac544ce036e7f9513a23b2ad085b7489c 100644 --- a/client/src/app/instance/search/pipes/sort-by-detail-display.ts +++ b/client/src/app/instance/search/pipes/sort-by-detail-display.ts @@ -14,6 +14,6 @@ import { Attribute } from 'src/app/metamodel/models'; @Pipe({name: 'sortByDetailDisplay'}) export class SortByDetailDisplay implements PipeTransform { transform(attributeList: Attribute[]): Attribute[] { - return [...attributeList].sort((a: Attribute, b: Attribute) => a.display_detail - b.display_detail); + return [...attributeList].sort((a: Attribute, b: Attribute) => a.detail_display - b.detail_display); } } diff --git a/client/src/app/instance/search/pipes/sort-by-output-display.pipe.spec.ts b/client/src/app/instance/search/pipes/sort-by-output-display.pipe.spec.ts index c760d9bd7f122bbf54fc65e2a470e396682668fe..f9b0dd9173e157d7988e27a504466b311161d1be 100644 --- a/client/src/app/instance/search/pipes/sort-by-output-display.pipe.spec.ts +++ b/client/src/app/instance/search/pipes/sort-by-output-display.pipe.spec.ts @@ -28,10 +28,7 @@ describe('[Instance][Search][Pipe] SortByOutputDisplayPipe', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -40,7 +37,8 @@ describe('[Instance][Search][Pipe] SortByOutputDisplayPipe', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }, { id: 1, @@ -64,10 +62,7 @@ describe('[Instance][Search][Pipe] SortByOutputDisplayPipe', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: null, vo_utype: null, vo_ucd: null, @@ -76,7 +71,8 @@ describe('[Instance][Search][Pipe] SortByOutputDisplayPipe', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null } ] expect(pipe.transform(attributeList)[0].id).toBe(1); diff --git a/client/src/app/instance/search/search-routing.module.ts b/client/src/app/instance/search/search-routing.module.ts index ffc569397e828e64c8c3374a733e02e11f1d0f5e..cec8354915ef48ce8d73543afcf52a9c0326c2b0 100644 --- a/client/src/app/instance/search/search-routing.module.ts +++ b/client/src/app/instance/search/search-routing.module.ts @@ -15,11 +15,9 @@ import { DatasetComponent } from './containers/dataset.component'; import { CriteriaComponent } from './containers/criteria.component'; import { OutputComponent } from './containers/output.component'; import { ResultComponent } from './containers/result.component'; -import { DetailComponent } from './containers/detail.component'; import { SearchAuthGuard } from './search-auth.guard'; const routes: Routes = [ - { path: 'detail/:dname/:id', component: DetailComponent }, { path: '', component: SearchComponent, children: [ { path: '', redirectTo: 'dataset', pathMatch: 'full' }, @@ -29,7 +27,8 @@ const routes: Routes = [ { path: 'output/:dname', canActivate: [SearchAuthGuard], component: OutputComponent }, { path: 'result/:dname', canActivate: [SearchAuthGuard], component: ResultComponent } ] - } + }, + { path: 'detail', loadChildren: () => import('./detail/detail.module').then(m => m.DetailModule) } ]; /** @@ -47,6 +46,5 @@ export const routedComponents = [ DatasetComponent, CriteriaComponent, OutputComponent, - ResultComponent, - DetailComponent + ResultComponent ]; diff --git a/client/src/app/instance/search/search.module.ts b/client/src/app/instance/search/search.module.ts index 2109154c13b7a32d7d1d041d86b59d1e95da69f4..e633fbb3bce0cf46b60004ea2d201630bda58b36 100644 --- a/client/src/app/instance/search/search.module.ts +++ b/client/src/app/instance/search/search.module.ts @@ -10,6 +10,7 @@ import { NgModule } from '@angular/core'; import { SharedModule } from 'src/app/shared/shared.module'; +// import { DynamicContentModule } from '../dynamic-content/dynamic-content.module'; import { ConeSearchModule } from '../cone-search/cone-search.module'; import { SearchRoutingModule, routedComponents } from './search-routing.module'; import { dummiesComponents } from './components'; @@ -22,6 +23,7 @@ import { searchPipes } from './pipes'; @NgModule({ imports: [ SharedModule, + //DynamicContentModule, ConeSearchModule, SearchRoutingModule ], diff --git a/client/src/app/instance/store/effects/detail.effects.spec.ts b/client/src/app/instance/store/effects/detail.effects.spec.ts index 641d716803bcb67f5e60ee0a84ad147ad9dcf2cb..6bedb172285c22e8c8ed3e0785bea087c838eeb4 100644 --- a/client/src/app/instance/store/effects/detail.effects.spec.ts +++ b/client/src/app/instance/store/effects/detail.effects.spec.ts @@ -94,10 +94,7 @@ describe('[Instance][Store] DetailEffects', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -106,7 +103,8 @@ describe('[Instance][Store] DetailEffects', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }] ); mockDetailSelectorSelectIdByRoute = store.overrideSelector( @@ -151,10 +149,7 @@ describe('[Instance][Store] DetailEffects', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -163,7 +158,8 @@ describe('[Instance][Store] DetailEffects', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }] ); mockDetailSelectorSelectIdByRoute = store.overrideSelector( diff --git a/client/src/app/instance/store/effects/detail.effects.ts b/client/src/app/instance/store/effects/detail.effects.ts index b1f2aa5f2bfec3d2c09c3aa7055ee309655cafff..893cd264252961faa68ed71f7e39ca460e14fda3 100644 --- a/client/src/app/instance/store/effects/detail.effects.ts +++ b/client/src/app/instance/store/effects/detail.effects.ts @@ -27,7 +27,6 @@ import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; */ @Injectable() export class DetailEffects { - /** * Calls actions to retrieve object. */ @@ -41,9 +40,8 @@ export class DetailEffects { ]), mergeMap(([, datasetName, attributeList, id]) => this.detailService.retrieveObject( datasetName, - attributeList.find(attribute => attribute.order_by).id, - id, - attributeList.filter(attribute => attribute.detail).map(attribute => attribute.id) + attributeList.find(attribute => attribute.primary_key).id, + id ).pipe( map(object => detailActions.retrieveObjectSuccess({ object: object[0] })), catchError(() => of(detailActions.retrieveObjectFail())) diff --git a/client/src/app/instance/store/effects/search.effects.spec.ts b/client/src/app/instance/store/effects/search.effects.spec.ts index 9ec12b8ff4348f6720824c388e68b518be14a06b..436528864caa23d27230d2df7402fa349e3e2bbf 100644 --- a/client/src/app/instance/store/effects/search.effects.spec.ts +++ b/client/src/app/instance/store/effects/search.effects.spec.ts @@ -301,10 +301,7 @@ describe('[Instance][Store] SearchEffects', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -313,7 +310,8 @@ describe('[Instance][Store] SearchEffects', () => { vo_datatype: null, vo_size: null, id_criteria_family: 1, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }, { id: 2, @@ -337,10 +335,7 @@ describe('[Instance][Store] SearchEffects', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -349,7 +344,8 @@ describe('[Instance][Store] SearchEffects', () => { vo_datatype: null, vo_size: null, id_criteria_family: 2, - id_output_category: null + id_output_category: null, + id_detail_output_category: null } ] ); @@ -404,10 +400,7 @@ describe('[Instance][Store] SearchEffects', () => { renderer_config: null, order_by: true, archive: false, - detail: false, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -416,7 +409,8 @@ describe('[Instance][Store] SearchEffects', () => { vo_datatype: null, vo_size: null, id_criteria_family: 1, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }, { id: 2, @@ -440,10 +434,7 @@ describe('[Instance][Store] SearchEffects', () => { renderer_config: null, order_by: true, archive: false, - detail: false, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -452,7 +443,8 @@ describe('[Instance][Store] SearchEffects', () => { vo_datatype: null, vo_size: null, id_criteria_family: 2, - id_output_category: null + id_output_category: null, + id_detail_output_category: null } ] ); @@ -540,10 +532,7 @@ describe('[Instance][Store] SearchEffects', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -552,7 +541,8 @@ describe('[Instance][Store] SearchEffects', () => { vo_datatype: null, vo_size: null, id_criteria_family: 1, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null }, { id: 2, @@ -576,10 +566,7 @@ describe('[Instance][Store] SearchEffects', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -588,7 +575,8 @@ describe('[Instance][Store] SearchEffects', () => { vo_datatype: null, vo_size: null, id_criteria_family: 2, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null } ] ); diff --git a/client/src/app/instance/store/models/criterion.model.spec.ts b/client/src/app/instance/store/models/criterion.model.spec.ts index 8c69afbe19d7a42259a3f13394de8ba8483789a3..d678d277b5f8603aa9057b4810543e338ada5df8 100644 --- a/client/src/app/instance/store/models/criterion.model.spec.ts +++ b/client/src/app/instance/store/models/criterion.model.spec.ts @@ -57,10 +57,7 @@ describe('[Instance][Store] CriterionModel', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -69,7 +66,8 @@ describe('[Instance][Store] CriterionModel', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }; let expected: Criterion = { id: 1, type: 'field', operator: 'neq', value: 'otherValue' } as FieldCriterion; expect(stringToCriterion(attribute, ['', 'neq', 'otherValue'])).toEqual(expected); @@ -95,10 +93,7 @@ describe('[Instance][Store] CriterionModel', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -107,7 +102,8 @@ describe('[Instance][Store] CriterionModel', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }; expected = { id: 1, type: 'field', operator: 'eq', value: 'value' } as FieldCriterion; expect(stringToCriterion(attribute)).toEqual(expected); @@ -133,10 +129,7 @@ describe('[Instance][Store] CriterionModel', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -145,7 +138,8 @@ describe('[Instance][Store] CriterionModel', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }; expected = { id: 1, type: 'list', values: ['one', 'two'] } as ListCriterion; expect(stringToCriterion(attribute, ['', '', 'one|two'])).toEqual(expected); @@ -171,10 +165,7 @@ describe('[Instance][Store] CriterionModel', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -183,7 +174,8 @@ describe('[Instance][Store] CriterionModel', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }; expected = { id: 1, type: 'list', values: ['valueA', 'valueB'] } as ListCriterion; expect(stringToCriterion(attribute)).toEqual(expected); @@ -209,10 +201,7 @@ describe('[Instance][Store] CriterionModel', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, options: null, vo_utype: null, vo_ucd: null, @@ -221,7 +210,8 @@ describe('[Instance][Store] CriterionModel', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }; expected = { id: 1, type: 'between', min: 'valueA', max: 'valueB' } as BetweenCriterion; expect(stringToCriterion(attribute, ['', 'bw', 'valueA|valueB'])).toEqual(expected); @@ -258,10 +248,7 @@ describe('[Instance][Store] CriterionModel', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, vo_utype: null, vo_ucd: null, vo_unit: null, @@ -269,7 +256,8 @@ describe('[Instance][Store] CriterionModel', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }; expected = { id: 1, type: 'multiple', options: [{ label: 'one', value: '1', display: 1 }, { label: 'three', value: '3', display: 3 }] } as SelectMultipleCriterion; expect(stringToCriterion(attribute, ['', '', '1|3'])).toEqual(expected); @@ -300,10 +288,7 @@ describe('[Instance][Store] CriterionModel', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, vo_utype: null, vo_ucd: null, vo_unit: null, @@ -311,7 +296,8 @@ describe('[Instance][Store] CriterionModel', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }; expected = { id: 1, type: 'multiple', options: [{ label: 'one', value: '1', display: 1 }, { label: 'two', value: '2', display: 2 }] } as SelectMultipleCriterion; expect(stringToCriterion(attribute)).toEqual(expected); @@ -338,10 +324,7 @@ describe('[Instance][Store] CriterionModel', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, vo_utype: null, vo_ucd: null, vo_unit: null, @@ -349,7 +332,8 @@ describe('[Instance][Store] CriterionModel', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }; expected = { id: 1, type: 'json', path: 'path', operator: 'op', value: 'value' } as JsonCriterion; expect(stringToCriterion(attribute, ['', '', 'path|op|value'])).toEqual(expected); @@ -376,10 +360,7 @@ describe('[Instance][Store] CriterionModel', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, vo_utype: null, vo_ucd: null, vo_unit: null, @@ -387,7 +368,8 @@ describe('[Instance][Store] CriterionModel', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }; expect(stringToCriterion(attribute)).toEqual(expected); attribute = { @@ -413,10 +395,7 @@ describe('[Instance][Store] CriterionModel', () => { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 1, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 1, vo_utype: null, vo_ucd: null, vo_unit: null, @@ -424,7 +403,8 @@ describe('[Instance][Store] CriterionModel', () => { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }; expect(stringToCriterion(attribute)).toBeNull(); }); diff --git a/client/src/app/instance/store/services/detail.service.spec.ts b/client/src/app/instance/store/services/detail.service.spec.ts index 5bac6d854bf16f91dee9e5fb58ce834ec094b12f..cd785472d58149784a713cde4e12f5f63a18dfdf 100644 --- a/client/src/app/instance/store/services/detail.service.spec.ts +++ b/client/src/app/instance/store/services/detail.service.spec.ts @@ -22,11 +22,11 @@ describe('[Instance][Store] DetailService', () => { inject([HttpTestingController, DetailService],(httpMock: HttpTestingController, detailService: DetailService) => { const mockResponse = ['myData']; - detailService.retrieveObject('myDataset', 1, 'myObject', [2,3]).subscribe((event: any[]) => { + detailService.retrieveObject('myDataset', 1, 'myObject').subscribe((event: any[]) => { expect(event).toEqual(mockResponse); }); - const mockRequest = httpMock.expectOne('http://testing.com/search/myDataset?c=1::eq::myObject&a=2;3'); + const mockRequest = httpMock.expectOne('http://testing.com/search/myDataset?c=1::eq::myObject&a=all'); expect(mockRequest.cancelled).toBeFalsy(); expect(mockRequest.request.responseType).toEqual('json'); diff --git a/client/src/app/instance/store/services/detail.service.ts b/client/src/app/instance/store/services/detail.service.ts index e9b644aa71907475302f8ffbc31187f4daa59ccd..eee2a6247e76bced3dff6964eccf3f89f4d84c40 100644 --- a/client/src/app/instance/store/services/detail.service.ts +++ b/client/src/app/instance/store/services/detail.service.ts @@ -32,8 +32,8 @@ export class DetailService { * * @return Observable<any[]> */ - retrieveObject(dname: string, criterionId: number, objectSelected: string, outputList: number[]): Observable<any[]> { - const query = `${dname}?c=${criterionId}::eq::${objectSelected}&a=${outputList.join(';')}`; + retrieveObject(dname: string, criterionId: number, objectSelected: string): Observable<any[]> { + const query = `${dname}?c=${criterionId}::eq::${objectSelected}&a=all`; return this.http.get<any[]>(`${this.config.apiUrl}/search/${query}`); } diff --git a/client/src/app/instance/dynamic-content/components/datatable.component.html b/client/src/app/instance/webpage/components/datatable.component.html similarity index 100% rename from client/src/app/instance/dynamic-content/components/datatable.component.html rename to client/src/app/instance/webpage/components/datatable.component.html diff --git a/client/src/app/instance/dynamic-content/components/datatable.component.ts b/client/src/app/instance/webpage/components/datatable.component.ts similarity index 100% rename from client/src/app/instance/dynamic-content/components/datatable.component.ts rename to client/src/app/instance/webpage/components/datatable.component.ts diff --git a/client/src/app/instance/webpage/components/index.ts b/client/src/app/instance/webpage/components/index.ts index 28c122e3ead6c199771514aeb447141d7880c7a0..cdbd83740a4c940c54f8449fce573b7fd98019b1 100644 --- a/client/src/app/instance/webpage/components/index.ts +++ b/client/src/app/instance/webpage/components/index.ts @@ -1,5 +1,7 @@ import { WebpageComponent } from './webpage-content.component'; +import { DatatableComponent } from './datatable.component'; export const dummiesComponents = [ - WebpageComponent + WebpageComponent, + DatatableComponent ]; diff --git a/client/src/app/instance/webpage/components/webpage-content.component.html b/client/src/app/instance/webpage/components/webpage-content.component.html index 99c5e9a4f9b14ba3431047af7a8c746abf86c8b0..5fff195df3ec184143772fe509157449a25c0c0b 100644 --- a/client/src/app/instance/webpage/components/webpage-content.component.html +++ b/client/src/app/instance/webpage/components/webpage-content.component.html @@ -1 +1 @@ -<ngx-dynamic-hooks [content]="webpage.content"></ngx-dynamic-hooks> \ No newline at end of file +<ngx-dynamic-hooks [content]="webpage.content" [parsers]="getParsers()"></ngx-dynamic-hooks> \ No newline at end of file diff --git a/client/src/app/instance/webpage/components/webpage-content.component.ts b/client/src/app/instance/webpage/components/webpage-content.component.ts index a8bfd9bbc62020da36e27f1b93e00eb397f52045..7559b9c51420858fc938a183b3b481c867ed4f29 100644 --- a/client/src/app/instance/webpage/components/webpage-content.component.ts +++ b/client/src/app/instance/webpage/components/webpage-content.component.ts @@ -7,9 +7,11 @@ * file that was distributed with this source code. */ -import { Component, Input } from '@angular/core'; +import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { Webpage } from 'src/app/metamodel/models'; +import { globalParsers } from 'src/app/shared/dynamic-content'; +import { componentParsers } from '../dynamic-content'; /** * @class @@ -17,8 +19,16 @@ import { Webpage } from 'src/app/metamodel/models'; */ @Component({ selector: 'app-webpage-content', - templateUrl: 'webpage-content.component.html' + templateUrl: 'webpage-content.component.html', + changeDetection: ChangeDetectionStrategy.OnPush }) export class WebpageComponent { @Input() webpage: Webpage; + + getParsers() { + return [ + ...globalParsers, + ...componentParsers + ]; + } } diff --git a/client/src/app/instance/dynamic-content/dynamic-components/dataset-sample.component.html b/client/src/app/instance/webpage/dynamic-content/dynamic-components/dataset-sample.component.html similarity index 100% rename from client/src/app/instance/dynamic-content/dynamic-components/dataset-sample.component.html rename to client/src/app/instance/webpage/dynamic-content/dynamic-components/dataset-sample.component.html diff --git a/client/src/app/instance/dynamic-content/dynamic-components/dataset-sample.component.ts b/client/src/app/instance/webpage/dynamic-content/dynamic-components/dataset-sample.component.ts similarity index 100% rename from client/src/app/instance/dynamic-content/dynamic-components/dataset-sample.component.ts rename to client/src/app/instance/webpage/dynamic-content/dynamic-components/dataset-sample.component.ts diff --git a/client/src/app/instance/webpage/dynamic-content/dynamic-components/index.ts b/client/src/app/instance/webpage/dynamic-content/dynamic-components/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..36671afce11b25c1cb064a8d3851b24b431cf5d4 --- /dev/null +++ b/client/src/app/instance/webpage/dynamic-content/dynamic-components/index.ts @@ -0,0 +1,5 @@ +import { DatasetSampleComponent } from './dataset-sample.component'; + +export const dynamicComponents = [ + DatasetSampleComponent +]; diff --git a/client/src/app/instance/webpage/dynamic-content/index.ts b/client/src/app/instance/webpage/dynamic-content/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a8a58f220117ec5118c9ca18d1f0e91af6ee7015 --- /dev/null +++ b/client/src/app/instance/webpage/dynamic-content/index.ts @@ -0,0 +1,14 @@ +import { HookParserEntry } from 'ngx-dynamic-hooks'; + +import { hookParsers } from './parsers'; +import { dynamicComponents } from './dynamic-components'; + +export const componentParsers: Array<HookParserEntry> = [ + ...hookParsers, + ...dynamicComponents.map(component => { + return { component }; + }) +]; + +export { hookParsers } from './parsers'; +export { dynamicComponents } from './dynamic-components'; diff --git a/client/src/app/instance/webpage/dynamic-content/parsers/index.ts b/client/src/app/instance/webpage/dynamic-content/parsers/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..552c5a60f42b85a8d485439c9086f2c80778140f --- /dev/null +++ b/client/src/app/instance/webpage/dynamic-content/parsers/index.ts @@ -0,0 +1,3 @@ +export const hookParsers = [ + +]; diff --git a/client/src/app/instance/webpage/webpage.module.ts b/client/src/app/instance/webpage/webpage.module.ts index 5bec1e05d2e46632e45e0dc24d0b376d975504ee..86a7baca4e2077dd36eda7b4a4eba995a96a4b8f 100644 --- a/client/src/app/instance/webpage/webpage.module.ts +++ b/client/src/app/instance/webpage/webpage.module.ts @@ -10,9 +10,9 @@ import { NgModule } from '@angular/core'; import { SharedModule } from 'src/app/shared/shared.module'; -import { DynamicContentModule } from '../dynamic-content/dynamic-content.module'; import { WebpageRoutingModule, routedComponents } from './webpage-routing.module'; import { dummiesComponents } from './components'; +import { hookParsers, dynamicComponents } from './dynamic-content'; /** * @class @@ -21,12 +21,18 @@ import { dummiesComponents } from './components'; @NgModule({ imports: [ SharedModule, - DynamicContentModule, WebpageRoutingModule, ], declarations: [ routedComponents, - dummiesComponents + dummiesComponents, + dynamicComponents + ], + entryComponents: [ + dynamicComponents + ], + providers: [ + hookParsers ] }) export class WebpageModule { } diff --git a/client/src/app/metamodel/actions/detail-config.actions.ts b/client/src/app/metamodel/actions/detail-config.actions.ts new file mode 100644 index 0000000000000000000000000000000000000000..685a2fdbae81f1997172e75a7f9b2ce840dc8a10 --- /dev/null +++ b/client/src/app/metamodel/actions/detail-config.actions.ts @@ -0,0 +1,22 @@ +/** + * 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 { createAction, props } from '@ngrx/store'; + +import { DetailConfig } from '../models'; + +export const loadDetailConfig = createAction('[Metamodel] Load Detail Config'); +export const loadDetailConfigSuccess = createAction('[Metamodel] Load Detail Config Success', props<{ detailConfig: DetailConfig }>()); +export const loadDetailConfigFail = createAction('[Metamodel] Load Detail Config Fail'); +export const addDetailConfig = createAction('[Metamodel] Add Detail Config', props<{ detailConfig: DetailConfig }>()); +export const addDetailConfigSuccess = createAction('[Metamodel] Add Detail Config Success', props<{ detailConfig: DetailConfig }>()); +export const addDetailConfigFail = createAction('[Metamodel] Add Detail Config Fail'); +export const editDetailConfig = createAction('[Metamodel] Edit Detail Config', props<{ detailConfig: DetailConfig }>()); +export const editDetailConfigSuccess = createAction('[Metamodel] Edit Detail Config Success', props<{ detailConfig: DetailConfig }>()); +export const editDetailConfigFail = createAction('[Metamodel] Edit Detail Config Fail'); diff --git a/client/src/app/metamodel/effects/detail-config.effects.ts b/client/src/app/metamodel/effects/detail-config.effects.ts new file mode 100644 index 0000000000000000000000000000000000000000..497015a88b8d6c0831ba40302bcb8fa2b2a45ba6 --- /dev/null +++ b/client/src/app/metamodel/effects/detail-config.effects.ts @@ -0,0 +1,122 @@ +/** + * 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 { Injectable } from '@angular/core'; + +import { Actions, createEffect, ofType, concatLatestFrom } from '@ngrx/effects'; +import { Store } from '@ngrx/store'; +import { of } from 'rxjs'; +import { map, tap, mergeMap, catchError } from 'rxjs/operators'; +import { ToastrService } from 'ngx-toastr'; + +import * as detailConfigActions from '../actions/detail-config.actions'; +import { DetailConfigService } from '../services/detail-config.service'; +import * as datasetSelector from '../selectors/dataset.selector'; + +/** + * @class + * @classdesc Detail effects. + */ +@Injectable() +export class DetailConfigEffects { + /** + * Calls action to retrieve detail configuration + */ + loadDetailsConfig$ = createEffect((): any => + this.actions$.pipe( + ofType(detailConfigActions.loadDetailConfig), + concatLatestFrom(() => this.store.select(datasetSelector.selectDatasetNameByRoute)), + mergeMap(([, datasetName]) => this.detailConfigService.retrieveDetailConfig(datasetName) + .pipe( + map(detailConfig => detailConfigActions.loadDetailConfigSuccess({ detailConfig })), + catchError(() => of(detailConfigActions.loadDetailConfigFail())) + ) + ) + ) + ); + + /** + * Calls action to add an detail. + */ + addDetailConfig$ = createEffect((): any => + this.actions$.pipe( + ofType(detailConfigActions.addDetailConfig), + concatLatestFrom(() => this.store.select(datasetSelector.selectDatasetNameByRoute)), + mergeMap(([action, datasetName]) => this.detailConfigService.addDetailConfig(datasetName, action.detailConfig) + .pipe( + map(detailConfig => detailConfigActions.addDetailConfigSuccess({ detailConfig })), + catchError(() => of(detailConfigActions.addDetailConfigFail())) + ) + ) + ) + ); + + /** + * Displays add detail configuration success notification. + */ + addDetailConfigSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(detailConfigActions.addDetailConfigSuccess), + tap(() => this.toastr.success('Detail config successfully added', 'The new detail config was added into the database')) + ), { dispatch: false } + ); + + /** + * Displays add detail configuration error notification. + */ + addDetailConfigFail$ = createEffect(() => + this.actions$.pipe( + ofType(detailConfigActions.addDetailConfigFail), + tap(() => this.toastr.error('Failure to add detail config', 'The new detail config could not be added into the database')) + ), { dispatch: false } + ); + + /** + * Calls action to modify an detail configuration + */ + editDetailConfig$ = createEffect((): any => + this.actions$.pipe( + ofType(detailConfigActions.editDetailConfig), + concatLatestFrom(() => this.store.select(datasetSelector.selectDatasetNameByRoute)), + mergeMap(([action, datasetName]) => this.detailConfigService.editDetailConfig(datasetName, action.detailConfig) + .pipe( + map(detailConfig => detailConfigActions.editDetailConfigSuccess({ detailConfig })), + catchError(() => of(detailConfigActions.editDetailConfigFail())) + ) + ) + ) + ); + + /** + * Displays edit detail configuration success notification. + */ + editDetailConfigSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(detailConfigActions.editDetailConfigSuccess), + tap(() => this.toastr.success('Detail configuration successfully edited', 'The existing detail configuration has been edited into the database')) + ), { dispatch: false } + ); + + /** + * Displays edit detail configuration error notification. + */ + editDetailConfigFail$ = createEffect(() => + this.actions$.pipe( + ofType(detailConfigActions.editDetailConfigFail), + tap(() => this.toastr.error('Failure to edit detail configuration', 'The existing detail configuration could not be edited into the database')) + ), { dispatch: false } + ); + + constructor( + private actions$: Actions, + private detailConfigService: DetailConfigService, + private toastr: ToastrService, + private store: Store<{ }> + ) {} +} diff --git a/client/src/app/metamodel/effects/index.ts b/client/src/app/metamodel/effects/index.ts index 9f2e2fc1b4e1f176e4ee57b683a368506214a3ac..4975891556f58baac43642c3fcc91a363cd8c36c 100644 --- a/client/src/app/metamodel/effects/index.ts +++ b/client/src/app/metamodel/effects/index.ts @@ -20,6 +20,7 @@ import { OutputFamilyEffects } from './output-family.effects'; import { ImageEffects } from './image.effects'; import { FileEffects } from './file.effects'; import { ConeSearchConfigEffects } from './cone-search-config.effects' +import { DetailConfigEffects } from './detail-config.effects'; import { WebpageFamilyEffects } from './webpage-family.effects'; import { WebpageEffects } from './webpage.effects'; @@ -37,6 +38,7 @@ export const metamodelEffects = [ ImageEffects, FileEffects, ConeSearchConfigEffects, + DetailConfigEffects, WebpageFamilyEffects, WebpageEffects ]; diff --git a/client/src/app/metamodel/metamodel.reducer.ts b/client/src/app/metamodel/metamodel.reducer.ts index 017bb208bf52fad13a7d7d9ffef312fd6bdd2e3b..c77c467c0e4915591d57616135193498a2c5d424 100644 --- a/client/src/app/metamodel/metamodel.reducer.ts +++ b/client/src/app/metamodel/metamodel.reducer.ts @@ -23,6 +23,7 @@ import * as outputFamily from './reducers/output-family.reducer'; import * as image from './reducers/image.reducer'; import * as file from './reducers/file.reducer'; import * as coneSearchConfig from './reducers/cone-search-config.reducer'; +import * as detailConfig from './reducers/detail-config.reducer'; import * as webpageFamily from './reducers/webpage-family.reducer'; import * as webpage from './reducers/webpage.reducer'; @@ -45,6 +46,7 @@ export interface State { image: image.State; file: file.State; coneSearchConfig: coneSearchConfig.State; + detailConfig: detailConfig.State; webpageFamily: webpageFamily.State; webpage: webpage.State; } @@ -63,6 +65,7 @@ const reducers = { image: image.imageReducer, file: file.fileReducer, coneSearchConfig: coneSearchConfig.coneSearchConfigReducer, + detailConfig: detailConfig.detailConfigReducer, webpageFamily: webpageFamily.webpageFamilyReducer, webpage: webpage.webpageReducer }; diff --git a/client/src/app/metamodel/models/attribute.model.ts b/client/src/app/metamodel/models/attribute.model.ts index ec8a1f3dad0c7150f3d8bfbe37c864d8d5b29474..ab96827eca36153c04b2b853ea1f47c5b6ccd7e5 100644 --- a/client/src/app/metamodel/models/attribute.model.ts +++ b/client/src/app/metamodel/models/attribute.model.ts @@ -9,7 +9,6 @@ import { Option } from './option.model'; import { RendererConfig } from './renderers'; -import { DetailRendererConfig } from './detail-renderers'; /** * Interface for attribute. @@ -38,10 +37,7 @@ export interface Attribute { renderer_config: RendererConfig; order_by: boolean; archive: boolean; - detail: boolean; - display_detail: number; - renderer_detail: string; - renderer_detail_config: DetailRendererConfig; + detail_display: number; options: Option[]; vo_utype: string; vo_ucd: string; @@ -51,4 +47,5 @@ export interface Attribute { vo_size: number; id_criteria_family: number; id_output_category: number; + id_detail_output_category: number; } diff --git a/client/src/app/metamodel/models/detail-renderers/detail-renderer-config.model.ts b/client/src/app/metamodel/models/detail-config.model.ts similarity index 62% rename from client/src/app/metamodel/models/detail-renderers/detail-renderer-config.model.ts rename to client/src/app/metamodel/models/detail-config.model.ts index 2eca974a42fef44681b51552cb6a0a69c8327e54..52f3e6559af5db34257bf1fd7bc6a997715e0b59 100644 --- a/client/src/app/metamodel/models/detail-renderers/detail-renderer-config.model.ts +++ b/client/src/app/metamodel/models/detail-config.model.ts @@ -8,10 +8,12 @@ */ /** - * Interface for renderer config. + * Interface for detail config. * - * @interface DetailRendererConfig + * @interface DetailConfig */ -export interface DetailRendererConfig { - id: 'detail-renderer-config'; -} +export interface DetailConfig { + id: number; + enabled: boolean; + content: string; +} \ No newline at end of file diff --git a/client/src/app/metamodel/models/detail-renderers/index.ts b/client/src/app/metamodel/models/detail-renderers/index.ts deleted file mode 100644 index 0ffe3fbd3e6b5d98f4e5f95ad5416cd21cd15d14..0000000000000000000000000000000000000000 --- a/client/src/app/metamodel/models/detail-renderers/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './detail-renderer-config.model'; -export * from './spectra-graph-renderer-config.model'; diff --git a/client/src/app/metamodel/models/detail-renderers/spectra-graph-renderer-config.model.ts b/client/src/app/metamodel/models/detail-renderers/spectra-graph-renderer-config.model.ts deleted file mode 100644 index 2390fd9a29fa19929c55fc1b447d3982c532021b..0000000000000000000000000000000000000000 --- a/client/src/app/metamodel/models/detail-renderers/spectra-graph-renderer-config.model.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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 { DetailRendererConfig } from './detail-renderer-config.model'; - -/** - * Interface for sprectra graph renderer config. - * - * @interface SpectraGraphRendererConfig - * @extends DetailRendererConfig - */ -export interface SpectraGraphRendererConfig extends DetailRendererConfig { - z: number; -} diff --git a/client/src/app/metamodel/models/index.ts b/client/src/app/metamodel/models/index.ts index 976dea69f42d52915527e4df612fd2a076f406e0..12e9e400a19a77764cc1c28aad386786e3b0fec9 100644 --- a/client/src/app/metamodel/models/index.ts +++ b/client/src/app/metamodel/models/index.ts @@ -20,8 +20,8 @@ export * from './output-category.model'; export * from './output-family.model'; export * from './image.model'; export * from './renderers'; -export * from './detail-renderers'; export * from './cone-search-config.model'; +export * from './detail-config.model'; export * from './file.model'; export * from './webpage.model'; export * from './webpage-family'; diff --git a/client/src/app/metamodel/reducers/detail-config.reducer.ts b/client/src/app/metamodel/reducers/detail-config.reducer.ts new file mode 100644 index 0000000000000000000000000000000000000000..9abac1dc8a8dd82534ac10ea8bfa3146310171c8 --- /dev/null +++ b/client/src/app/metamodel/reducers/detail-config.reducer.ts @@ -0,0 +1,72 @@ +/** + * 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 { createReducer, on } from '@ngrx/store'; + +import { DetailConfig } from '../models'; +import * as detailActions from '../actions/detail-config.actions'; + +/** + * Interface for detail state. + * + * @interface State + */ +export interface State { + detailConfig: DetailConfig; + detailConfigIsLoading: boolean; + detailConfigIsLoaded: boolean; +} + +export const initialState: State = { + detailConfig: null, + detailConfigIsLoading: false, + detailConfigIsLoaded: false +}; + +export const detailConfigReducer = createReducer( + initialState, + on(detailActions.loadDetailConfig, (state) => { + return { + ...state, + detailConfig: null, + detailConfigIsLoading: true, + detailConfigIsLoaded: false + } + }), + on(detailActions.loadDetailConfigSuccess, (state, { detailConfig }) => { + return { + ...state, + detailConfig, + detailConfigIsLoading: false, + detailConfigIsLoaded: true + } + }), + on(detailActions.loadDetailConfigFail, (state) => { + return { + ...state, + detailConfigIsLoading: false + } + }), + on(detailActions.addDetailConfigSuccess, (state, { detailConfig }) => { + return { + ...state, + detailConfig + } + }), + on(detailActions.editDetailConfigSuccess, (state, { detailConfig }) => { + return { + ...state, + detailConfig + } + }) +); + +export const selectDetailConfig = (state: State) => state.detailConfig; +export const selectDetailConfigIsLoading = (state: State) => state.detailConfigIsLoading; +export const selectDetailConfigIsLoaded = (state: State) => state.detailConfigIsLoaded; diff --git a/client/src/app/metamodel/selectors/detail-config.selector.ts b/client/src/app/metamodel/selectors/detail-config.selector.ts new file mode 100644 index 0000000000000000000000000000000000000000..211496fe7267636c933d74c8db5e23aee62dd68d --- /dev/null +++ b/client/src/app/metamodel/selectors/detail-config.selector.ts @@ -0,0 +1,33 @@ +/** + * 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 { createSelector } from '@ngrx/store'; + +import * as reducer from '../metamodel.reducer'; +import * as fromDetailConfig from '../reducers/detail-config.reducer'; + +export const selectDetailConfigState = createSelector( + reducer.getMetamodelState, + (state: reducer.State) => state.detailConfig +); + +export const selectDetailConfig = createSelector( + selectDetailConfigState, + fromDetailConfig.selectDetailConfig +); + +export const selectDetailConfigIsLoading = createSelector( + selectDetailConfigState, + fromDetailConfig.selectDetailConfigIsLoading +); + +export const selectDetailConfigIsLoaded = createSelector( + selectDetailConfigState, + fromDetailConfig.selectDetailConfigIsLoaded +); diff --git a/client/src/app/metamodel/services/detail-config.service.ts b/client/src/app/metamodel/services/detail-config.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..3a2b08063945d47503888c5b629bbc34f10c4d0c --- /dev/null +++ b/client/src/app/metamodel/services/detail-config.service.ts @@ -0,0 +1,57 @@ +/** + * 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 { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +import { Observable } from 'rxjs'; + +import { DetailConfig } from '../models'; +import { AppConfigService } from 'src/app/app-config.service'; + +/** + * @class + * @classdesc detail configuration service. + */ +@Injectable() +export class DetailConfigService { + constructor(private http: HttpClient, private config: AppConfigService) { } + + /** + * Retrieves detail configuration + * + * @return Observable<DetailConfig> + */ + retrieveDetailConfig(datasetName: string): Observable<DetailConfig> { + return this.http.get<DetailConfig>(`${this.config.apiUrl}/dataset/${datasetName}/detail-config`); + } + + /** + * Adds a new detail configuration for the given dataset. + * + * @param {string} datasetName - The dataset name. + * @param {Detail} newDetailConfig - The detail configuration. + * + * @return Observable<DetailConfig> + */ + addDetailConfig(datasetName: string, newDetailConfig: DetailConfig): Observable<DetailConfig> { + return this.http.post<DetailConfig>(`${this.config.apiUrl}/dataset/${datasetName}/detail-config`, newDetailConfig); + } + + /** + * Modifies detail configuration. + * + * @param {Detail} detailConfig - The detail cofiguration. + * + * @return Observable<DetailConfig> + */ + editDetailConfig(datasetName: string, detailConfig: DetailConfig): Observable<DetailConfig> { + return this.http.put<DetailConfig>(`${this.config.apiUrl}/dataset/${datasetName}/detail-config`, detailConfig); + } +} diff --git a/client/src/app/metamodel/services/index.ts b/client/src/app/metamodel/services/index.ts index 1c670871ca257a1f0da700f2ce2f45baa6e8fcd7..b2588fe9038f588cb611dd7c7c69997c19a3b2e7 100644 --- a/client/src/app/metamodel/services/index.ts +++ b/client/src/app/metamodel/services/index.ts @@ -20,6 +20,7 @@ import { OutputFamilyService } from './output-family.service'; import { ImageService } from './image.service'; import { FileService } from './file.service'; import { ConeSearchConfigService } from './cone-search-config.service'; +import { DetailConfigService } from './detail-config.service'; import { WebpageFamilyService } from './webpage-family.service'; import { WebpageService } from './webpage.service'; @@ -37,6 +38,7 @@ export const metamodelServices = [ ImageService, FileService, ConeSearchConfigService, + DetailConfigService, WebpageFamilyService, WebpageService ]; diff --git a/client/src/app/instance/dynamic-content/dynamic-components/dynamic-router-link.component.html b/client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.html similarity index 100% rename from client/src/app/instance/dynamic-content/dynamic-components/dynamic-router-link.component.html rename to client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.html diff --git a/client/src/app/instance/dynamic-content/dynamic-components/dynamic-router-link.component.scss b/client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.scss similarity index 100% rename from client/src/app/instance/dynamic-content/dynamic-components/dynamic-router-link.component.scss rename to client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.scss diff --git a/client/src/app/instance/dynamic-content/dynamic-components/dynamic-router-link.component.ts b/client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.ts similarity index 100% rename from client/src/app/instance/dynamic-content/dynamic-components/dynamic-router-link.component.ts rename to client/src/app/shared/dynamic-content/dynamic-components/dynamic-router-link.component.ts diff --git a/client/src/app/shared/dynamic-content/dynamic-components/index.ts b/client/src/app/shared/dynamic-content/dynamic-components/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..376e8a427ccae25fc2bd6090b24f59785feb858a --- /dev/null +++ b/client/src/app/shared/dynamic-content/dynamic-components/index.ts @@ -0,0 +1,5 @@ +import { DynamicRouterLinkComponent } from './dynamic-router-link.component'; + +export const dynamicComponents = [ + DynamicRouterLinkComponent +]; diff --git a/client/src/app/shared/dynamic-content/index.ts b/client/src/app/shared/dynamic-content/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..98122e3a81ef2561c55476df774861dfda839d67 --- /dev/null +++ b/client/src/app/shared/dynamic-content/index.ts @@ -0,0 +1,14 @@ +import { HookParserEntry } from 'ngx-dynamic-hooks'; + +import { hookParsers } from './parsers'; +import { dynamicComponents } from './dynamic-components'; + +export const globalParsers: Array<HookParserEntry> = [ + ...hookParsers, + ...dynamicComponents.map(component => { + return { component }; + }) +]; + +export { hookParsers } from './parsers'; +export { dynamicComponents } from './dynamic-components'; diff --git a/client/src/app/instance/dynamic-content/parsers/dynamic-router-link-parser.ts b/client/src/app/shared/dynamic-content/parsers/dynamic-router-link-parser.ts similarity index 99% rename from client/src/app/instance/dynamic-content/parsers/dynamic-router-link-parser.ts rename to client/src/app/shared/dynamic-content/parsers/dynamic-router-link-parser.ts index cb543c79b8a96b1d49c935f44f88045eef4ee3d9..01b5fa6eaeea8bd6c29a5e2bdf326d822472159d 100644 --- a/client/src/app/instance/dynamic-content/parsers/dynamic-router-link-parser.ts +++ b/client/src/app/shared/dynamic-content/parsers/dynamic-router-link-parser.ts @@ -21,7 +21,7 @@ export class DynamicRouterLinkParser implements HookParser { this.linkClosingTagRegex = new RegExp('<\\/a>', 'gim'); this.hrefAttrRegex = new RegExp(hrefAttr, 'im'); this.classAttrRegex = new RegExp('\\s+class\=\\"([^\\"]*?)\\"', 'im'); - this.targetAttrRegex = new RegExp('\\s+target\=\\"([^\\"]*?)\\"', 'im') + this.targetAttrRegex = new RegExp('\\s+target\=\\"([^\\"]*?)\\"', 'im'); } public findHooks(content: string, context: any): Array<HookPosition> { diff --git a/client/src/app/instance/dynamic-content/parsers/index.ts b/client/src/app/shared/dynamic-content/parsers/index.ts similarity index 100% rename from client/src/app/instance/dynamic-content/parsers/index.ts rename to client/src/app/shared/dynamic-content/parsers/index.ts diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 5455dacaf03013492277fba8166c698db0219f76..750a89c0234ed6dca33bf93335087f5b2c6bc379 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts @@ -23,9 +23,11 @@ import { PaginationModule } from 'ngx-bootstrap/pagination'; import { ProgressbarModule } from 'ngx-bootstrap/progressbar'; import { NgSelectModule } from '@ng-select/ng-select'; import { NgxJsonViewerModule } from 'ngx-json-viewer'; +import { DynamicHooksModule } from 'ngx-dynamic-hooks'; import { sharedComponents } from './components'; import { sharedPipes } from './pipes'; +import { hookParsers, dynamicComponents } from './dynamic-content'; /** * @class @@ -34,7 +36,14 @@ import { sharedPipes } from './pipes'; @NgModule({ declarations: [ sharedComponents, - sharedPipes + sharedPipes, + dynamicComponents + ], + entryComponents: [ + dynamicComponents + ], + providers: [ + hookParsers ], imports: [ CommonModule, @@ -51,7 +60,8 @@ import { sharedPipes } from './pipes'; PaginationModule.forRoot(), ProgressbarModule.forRoot(), NgSelectModule, - NgxJsonViewerModule + NgxJsonViewerModule, + DynamicHooksModule.forRoot({}), ], exports: [ CommonModule, @@ -68,8 +78,10 @@ import { sharedPipes } from './pipes'; ProgressbarModule, NgSelectModule, NgxJsonViewerModule, + DynamicHooksModule, sharedComponents, - sharedPipes + sharedPipes, + dynamicComponents ] }) export class SharedModule { } diff --git a/client/src/test-data.ts b/client/src/test-data.ts index 40464d8233914649c8fddb66f59687f6158ef2cd..c1a031a9b1e8709956003aa010f42067241b4510 100644 --- a/client/src/test-data.ts +++ b/client/src/test-data.ts @@ -248,10 +248,7 @@ export const ATTRIBUTE_LIST: Attribute[] = [ renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -264,7 +261,8 @@ export const ATTRIBUTE_LIST: Attribute[] = [ vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 2 + id_output_category: 2, + id_detail_output_category: null }, { id: 2, @@ -288,10 +286,7 @@ export const ATTRIBUTE_LIST: Attribute[] = [ renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -304,7 +299,8 @@ export const ATTRIBUTE_LIST: Attribute[] = [ vo_datatype: null, vo_size: null, id_criteria_family: 1, - id_output_category: 1 + id_output_category: 1, + id_detail_output_category: null }, { id: 3, @@ -328,10 +324,7 @@ export const ATTRIBUTE_LIST: Attribute[] = [ renderer_config: null, order_by: true, archive: false, - detail: false, - display_detail: 3, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 3, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -344,7 +337,8 @@ export const ATTRIBUTE_LIST: Attribute[] = [ vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: null + id_output_category: null, + id_detail_output_category: null }, { id: 4, @@ -368,10 +362,7 @@ export const ATTRIBUTE_LIST: Attribute[] = [ renderer_config: null, order_by: true, archive: false, - detail: false, - display_detail: 4, - renderer_detail: 'spectra_graph', - renderer_detail_config: null, + detail_display: 4, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -385,6 +376,7 @@ export const ATTRIBUTE_LIST: Attribute[] = [ vo_size: null, id_criteria_family: null, id_output_category: 1, + id_detail_output_category: null } ]; @@ -410,10 +402,7 @@ export const ATTRIBUTE: Attribute = { renderer_config: null, order_by: true, archive: false, - detail: true, - display_detail: 2, - renderer_detail: null, - renderer_detail_config: null, + detail_display: 2, options: [ { label: 'Three', value: 'three', display: 3 }, { label: 'One', value: 'one', display: 1 }, @@ -426,7 +415,8 @@ export const ATTRIBUTE: Attribute = { vo_datatype: null, vo_size: null, id_criteria_family: null, - id_output_category: 2 + id_output_category: 2, + id_detail_output_category: null }; export const COLUMN_LIST: Column[] = [ diff --git a/conf-dev/create-db.sh b/conf-dev/create-db.sh index 85345caa90455d1001ccb6a8443c2682d4593b2b..0136c54f99c67ca202c72a8dc41a406ea75494a8 100644 --- a/conf-dev/create-db.sh +++ b/conf-dev/create-db.sh @@ -27,36 +27,39 @@ curl -d '{"label":"Default","display":10,"opened":true}' --header 'Content-Type: curl -d '{"label":"Default","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/output-family curl -d '{"label":"Default","display":10}' --header 'Content-Type: application/json' -X POST http://localhost/output-family/1/output-category -curl -d '{"id":1,"name":"num","label":"num","form_label":"num","description":null,"primary_key":true,"output_display":10,"criteria_display":10,"search_type":"field","type":"decimal","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"detail-link","renderer_config":{"display":"text","blank":true},"display_detail":10,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":2,"name":"alpha","label":"alpha","form_label":"alpha","description":null,"primary_key":false,"output_display":20,"criteria_display":20,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":20,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":3,"name":"delta","label":"delta","form_label":"delta","description":null,"primary_key":false,"output_display":30,"criteria_display":30,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":30,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":4,"name":"selmag","label":"selmag","form_label":"selmag","description":null,"primary_key":false,"output_display":40,"criteria_display":40,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":40,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":5,"name":"errselmag","label":"errselmag","form_label":"errselmag","description":null,"primary_key":false,"output_display":50,"criteria_display":50,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":50,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":6,"name":"pointing","label":"pointing","form_label":"pointing","description":null,"primary_key":false,"output_display":60,"criteria_display":60,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":60,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":7,"name":"quadrant","label":"quadrant","form_label":"quadrant","description":null,"primary_key":false,"output_display":70,"criteria_display":70,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":70,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":8,"name":"zspec","label":"zspec","form_label":"zspec","description":null,"primary_key":false,"output_display":80,"criteria_display":80,"search_type":"between","type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":80,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":9,"name":"zflg","label":"zflg","form_label":"zflg","description":null,"primary_key":false,"output_display":90,"criteria_display":90,"search_type":"datalist","type":"decimal","operator":"in","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":90,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":[{"label":"1,2,3,4,9","value":"1,2,3,4,9","display":10},{"label":"2,3,4,9","value":"2,3,4,9","display":20},{"label":"3,4","value":"3,4","display":30},{"label":"1,2,3,4,9,21,22,23,24,29","value":"1,2,3,4,9,21,22,23,24,29","display":40},{"label":"2,3,4,9,22,23,24,29","value":"2,3,4,9,22,23,24,29","display":50}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":10,"name":"norm","label":"norm","form_label":"norm","description":null,"primary_key":false,"output_display":100,"criteria_display":100,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":100,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":11,"name":"epoch","label":"epoch","form_label":"epoch","description":null,"primary_key":false,"output_display":110,"criteria_display":110,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":110,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":12,"name":"photomask","label":"photomask","form_label":"photomask","description":null,"primary_key":false,"output_display":120,"criteria_display":120,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":120,"selected":true,"order_by":true,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":56,"name":"spec1d","label":"spec1d","form_label":"spec1d","description":null,"primary_key":false,"output_display":560,"criteria_display":560,"search_type":null,"type":"text","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"display_detail":560,"selected":true,"order_by":false,"archive":false,"detail":true,"renderer_detail":"spectra_graph","renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":57,"name":"spec1dnoise","label":"spec1dnoise","form_label":"spec1dnoise","description":null,"primary_key":false,"output_display":570,"criteria_display":570,"search_type":null,"type":"text","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"display_detail":570,"selected":true,"order_by":false,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute -curl -d '{"id":58,"name":"spec1dsky","label":"spec1dsky","form_label":"spec1dsky","description":null,"primary_key":false,"output_display":580,"criteria_display":580,"search_type":null,"type":"text","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"display_detail":580,"selected":true,"order_by":false,"archive":false,"detail":true,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":1,"name":"num","label":"num","form_label":"num","description":null,"primary_key":true,"output_display":10,"criteria_display":10,"search_type":"field","type":"decimal","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"detail-link","renderer_config":{"display":"text"},"detail_display":10,"selected":true,"order_by":true,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":2,"name":"alpha","label":"alpha","form_label":"alpha","description":null,"primary_key":false,"output_display":20,"criteria_display":20,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":20,"selected":true,"order_by":true,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":3,"name":"delta","label":"delta","form_label":"delta","description":null,"primary_key":false,"output_display":30,"criteria_display":30,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":30,"selected":true,"order_by":true,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":4,"name":"selmag","label":"selmag","form_label":"selmag","description":null,"primary_key":false,"output_display":40,"criteria_display":40,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":40,"selected":true,"order_by":true,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":5,"name":"errselmag","label":"errselmag","form_label":"errselmag","description":null,"primary_key":false,"output_display":50,"criteria_display":50,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":50,"selected":true,"order_by":true,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":6,"name":"pointing","label":"pointing","form_label":"pointing","description":null,"primary_key":false,"output_display":60,"criteria_display":60,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":60,"selected":true,"order_by":true,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":7,"name":"quadrant","label":"quadrant","form_label":"quadrant","description":null,"primary_key":false,"output_display":70,"criteria_display":70,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":70,"selected":true,"order_by":true,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":8,"name":"zspec","label":"zspec","form_label":"zspec","description":null,"primary_key":false,"output_display":80,"criteria_display":80,"search_type":"between","type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":80,"selected":true,"order_by":true,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":9,"name":"zflg","label":"zflg","form_label":"zflg","description":null,"primary_key":false,"output_display":90,"criteria_display":90,"search_type":"datalist","type":"decimal","operator":"in","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":90,"selected":true,"order_by":true,"archive":false,"options":[{"label":"1,2,3,4,9","value":"1,2,3,4,9","display":10},{"label":"2,3,4,9","value":"2,3,4,9","display":20},{"label":"3,4","value":"3,4","display":30},{"label":"1,2,3,4,9,21,22,23,24,29","value":"1,2,3,4,9,21,22,23,24,29","display":40},{"label":"2,3,4,9,22,23,24,29","value":"2,3,4,9,22,23,24,29","display":50}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":10,"name":"norm","label":"norm","form_label":"norm","description":null,"primary_key":false,"output_display":100,"criteria_display":100,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":100,"selected":true,"order_by":true,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":11,"name":"epoch","label":"epoch","form_label":"epoch","description":null,"primary_key":false,"output_display":110,"criteria_display":110,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":110,"selected":true,"order_by":true,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":null,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":12,"name":"photomask","label":"photomask","form_label":"photomask","description":null,"primary_key":false,"output_display":120,"criteria_display":120,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":120,"selected":true,"order_by":true,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":null,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":56,"name":"spec1d","label":"spec1d","form_label":"spec1d","description":null,"primary_key":false,"output_display":560,"criteria_display":560,"search_type":null,"type":"text","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"detail_display":560,"selected":true,"order_by":false,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":57,"name":"spec1dnoise","label":"spec1dnoise","form_label":"spec1dnoise","description":null,"primary_key":false,"output_display":570,"criteria_display":570,"search_type":null,"type":"text","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"detail_display":570,"selected":true,"order_by":false,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute +curl -d '{"id":58,"name":"spec1dsky","label":"spec1dsky","form_label":"spec1dsky","description":null,"primary_key":false,"output_display":580,"criteria_display":580,"search_type":null,"type":"text","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"detail_display":580,"selected":true,"order_by":false,"archive":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":1,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/attribute + +# Add vipers_dr2_w1 detail config +curl -d '{"enabled":true,"content":"<div class=\"row\">\n <div class=\"col col-md-8 col-sm-12\">\n <app-display-spectra\n [object]=\"context.object\"\n [datasetName]=\"context.datasetName\"\n [attributeList]=\"context.attributeList\"\n [attributeSpectraId]=\"56\"\n [attributeZId]=\"8\">\n </app-display-spectra>\n </div>\n <div class=\"col col-md-4 col-sm-12\">\n <app-display-ra-dec\n [object]=\"context.object\"\n [attributeList]=\"context.attributeList\"\n [attributeRaId]=\"2\"\n [attributeDecId]=\"3\">\n </app-display-ra-dec>\n <app-display-object \n [object]=\"context.object\"\n [attributeList]=\"context.attributeList\"\n [outputFamilyList]=\"context.outputFamilyList\"\n [outputCategoryList]=\"context.outputCategoryList\">\n </app-display-object>\n </div>\n</div>"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vipers_dr2_w1/detail-config # Add sp_cards attributes curl -d '{"label":"Card","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/criteria-family curl -d '{"label":"Default","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/output-family curl -d '{"label":"Default","display":10}' --header 'Content-Type: application/json' -X POST http://localhost/output-family/2/output-category -curl -d '{"id":1,"name":"acronym","label":"acronym","form_label":"Product Acronym","description":null,"primary_key":true,"output_display":10,"criteria_display":10,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":[],"display_detail":10,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":[{"label":"LAMTEST","value":"LAMTEST","display":10},{"label":"LAMTEST_DC1","value":"LAMTEST_DC1","display":20},{"label":"MXT-EVT-CAL","value":"MXT-EVT-CAL","display":30},{"label":"OBLC_ECL","value":"OBLC_ECL","display":40}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":2,"id_output_category":2}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute -curl -d '{"id":2,"name":"sp_id","label":"sp_id","form_label":"SP IAP ID","description":null,"primary_key":false,"output_display":20,"criteria_display":20,"search_type":null,"type":"integer","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":20,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":2}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute -curl -d '{"id":3,"name":"version","label":"version","form_label":"Version","description":null,"primary_key":false,"output_display":30,"criteria_display":30,"search_type":null,"type":"float","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":30,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":2}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute -curl -d '{"id":4,"name":"program","label":"program","form_label":"Program","description":null,"primary_key":false,"output_display":40,"criteria_display":40,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":40,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":[{"label":"CP","value":"CP","display":10},{"label":"GP","value":"GP","display":20}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":2,"id_output_category":2}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute -curl -d '{"id":5,"name":"instrument","label":"instrument","form_label":"Instrument","description":null,"primary_key":false,"output_display":50,"criteria_display":50,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":50,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":[{"label":"ALL","value":"ALL","display":10},{"label":"MXT","value":"MXT","display":20}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":2,"id_output_category":2}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute -curl -d '{"id":6,"name":"type","label":"type","form_label":"Type","description":null,"primary_key":false,"output_display":60,"criteria_display":60,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":60,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":2}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute -curl -d '{"id":7,"name":"json_schema","label":"json_schema","form_label":"JSON Schema (original)","description":null,"primary_key":false,"output_display":70,"criteria_display":70,"search_type":null,"type":"json","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"json","renderer_config":[],"display_detail":70,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":2}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute -curl -d '{"id":8,"name":"search_kw","label":"search_kw","form_label":"KWs searchable","description":null,"primary_key":false,"output_display":80,"criteria_display":80,"search_type":null,"type":"json","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"json","renderer_config":[],"display_detail":80,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":2}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute -curl -d '{"id":9,"name":"json_schema_uploaded","label":"json_schema_uploaded","form_label":"json_schema_uploaded","description":null,"primary_key":false,"output_display":90,"criteria_display":90,"search_type":null,"type":"json","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":90,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute +curl -d '{"id":1,"name":"acronym","label":"acronym","form_label":"Product Acronym","description":null,"primary_key":true,"output_display":10,"criteria_display":10,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":[],"detail_display":10,"selected":true,"order_by":true,"archive":false,"detail":false,"options":[{"label":"LAMTEST","value":"LAMTEST","display":10},{"label":"LAMTEST_DC1","value":"LAMTEST_DC1","display":20},{"label":"MXT-EVT-CAL","value":"MXT-EVT-CAL","display":30},{"label":"OBLC_ECL","value":"OBLC_ECL","display":40}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":2,"id_output_category":2,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute +curl -d '{"id":2,"name":"sp_id","label":"sp_id","form_label":"SP IAP ID","description":null,"primary_key":false,"output_display":20,"criteria_display":20,"search_type":null,"type":"integer","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":20,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":2,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute +curl -d '{"id":3,"name":"version","label":"version","form_label":"Version","description":null,"primary_key":false,"output_display":30,"criteria_display":30,"search_type":null,"type":"float","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":30,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":2,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute +curl -d '{"id":4,"name":"program","label":"program","form_label":"Program","description":null,"primary_key":false,"output_display":40,"criteria_display":40,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":40,"selected":true,"order_by":true,"archive":false,"detail":false,"options":[{"label":"CP","value":"CP","display":10},{"label":"GP","value":"GP","display":20}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":2,"id_output_category":2,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute +curl -d '{"id":5,"name":"instrument","label":"instrument","form_label":"Instrument","description":null,"primary_key":false,"output_display":50,"criteria_display":50,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":50,"selected":true,"order_by":true,"archive":false,"detail":false,"options":[{"label":"ALL","value":"ALL","display":10},{"label":"MXT","value":"MXT","display":20}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":2,"id_output_category":2,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute +curl -d '{"id":6,"name":"type","label":"type","form_label":"Type","description":null,"primary_key":false,"output_display":60,"criteria_display":60,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":60,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":2,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute +curl -d '{"id":7,"name":"json_schema","label":"json_schema","form_label":"JSON Schema (original)","description":null,"primary_key":false,"output_display":70,"criteria_display":70,"search_type":null,"type":"json","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"json","renderer_config":[],"detail_display":70,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":2,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute +curl -d '{"id":8,"name":"search_kw","label":"search_kw","form_label":"KWs searchable","description":null,"primary_key":false,"output_display":80,"criteria_display":80,"search_type":null,"type":"json","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"json","renderer_config":[],"detail_display":80,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":2,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute +curl -d '{"id":9,"name":"json_schema_uploaded","label":"json_schema_uploaded","form_label":"json_schema_uploaded","description":null,"primary_key":false,"output_display":90,"criteria_display":90,"search_type":null,"type":"json","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":90,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":null,"id_detail_output_category":null,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/sp_cards/attribute # Add observations attributes curl -d '{"label":"Default","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/criteria-family @@ -64,28 +67,31 @@ curl -d '{"label":"Default parameters","display":10,"opened":true}' --header 'Co curl -d '{"label":"Astrometry","display":10}' --header 'Content-Type: application/json' -X POST http://localhost/output-family/3/output-category curl -d '{"label":"Observation","display":10}' --header 'Content-Type: application/json' -X POST http://localhost/output-family/3/output-category -curl -d '{"id":1,"name":"id","label":"id","form_label":"id","description":"Observation Ident","primary_key":true,"output_display":10,"criteria_display":10,"search_type":null,"type":"integer","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":10,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":3}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute -curl -d '{"id":2,"name":"ra","label":"ra","form_label":"Alpha J2000","description":"Alpha J2000","primary_key":false,"output_display":20,"criteria_display":20,"search_type":null,"type":"float","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":20,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":3}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute -curl -d '{"id":3,"name":"dec","label":"dec","form_label":"Delta J2000","description":"Delta J2000","primary_key":false,"output_display":30,"criteria_display":30,"search_type":null,"type":"float","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":30,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":3}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute -curl -d '{"id":4,"name":"date_time","label":"date_time","form_label":"Date Time","description":"Date Time","primary_key":false,"output_display":40,"criteria_display":40,"search_type":"between-date","type":"datetime","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":40,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":4}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute -curl -d '{"id":5,"name":"exposure_time","label":"exposure_time","form_label":"Exposure Time","description":"Exposure Time","primary_key":false,"output_display":50,"criteria_display":50,"search_type":"between","type":"integer","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":50,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":4}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute -curl -d '{"id":6,"name":"filter","label":"filter","form_label":"Filter","description":"Filter","primary_key":false,"output_display":60,"criteria_display":60,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":60,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":[{"label":"Halpha","value":"Halpha","display":10},{"label":"SDSS g","value":"SDSS g","display":20}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":4}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute -curl -d '{"id":7,"name":"object_name","label":"object_name","form_label":"Object name","description":"Object name","primary_key":false,"output_display":70,"criteria_display":70,"search_type":"field","type":"string","operator":"lk","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"link","renderer_config":{"href":"http:\/\/cdsportal.u-strasbg.fr\/?target=$value","display":"text","text":"$value","icon":"fas fa-link","blank":true},"display_detail":70,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":4}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute -curl -d '{"id":8,"name":"fits_file","label":"fits_file","form_label":"fits_file","description":null,"primary_key":false,"output_display":80,"criteria_display":80,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"display_detail":80,"selected":true,"order_by":false,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":4}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute -curl -d '{"id":9,"name":"fits_png","label":"fits_png","form_label":"fits_png","description":null,"primary_key":false,"output_display":90,"criteria_display":90,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"image","renderer_config":{"type":"fits","display":"modal","width":"50","height":"50"},"display_detail":90,"selected":true,"order_by":false,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":4}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute +curl -d '{"id":1,"name":"id","label":"id","form_label":"id","description":"Observation Ident","primary_key":true,"output_display":10,"criteria_display":10,"search_type":null,"type":"integer","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":10,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":3,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute +curl -d '{"id":2,"name":"ra","label":"ra","form_label":"Alpha J2000","description":"Alpha J2000","primary_key":false,"output_display":20,"criteria_display":20,"search_type":null,"type":"float","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":20,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":3,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute +curl -d '{"id":3,"name":"dec","label":"dec","form_label":"Delta J2000","description":"Delta J2000","primary_key":false,"output_display":30,"criteria_display":30,"search_type":null,"type":"float","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":30,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":3,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute +curl -d '{"id":4,"name":"date_time","label":"date_time","form_label":"Date Time","description":"Date Time","primary_key":false,"output_display":40,"criteria_display":40,"search_type":"between-date","type":"datetime","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":40,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":4,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute +curl -d '{"id":5,"name":"exposure_time","label":"exposure_time","form_label":"Exposure Time","description":"Exposure Time","primary_key":false,"output_display":50,"criteria_display":50,"search_type":"between","type":"integer","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":50,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":4,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute +curl -d '{"id":6,"name":"filter","label":"filter","form_label":"Filter","description":"Filter","primary_key":false,"output_display":60,"criteria_display":60,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":60,"selected":true,"order_by":true,"archive":false,"detail":false,"options":[{"label":"Halpha","value":"Halpha","display":10},{"label":"SDSS g","value":"SDSS g","display":20}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":4,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute +curl -d '{"id":7,"name":"object_name","label":"object_name","form_label":"Object name","description":"Object name","primary_key":false,"output_display":70,"criteria_display":70,"search_type":"field","type":"string","operator":"lk","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"link","renderer_config":{"href":"http:\/\/cdsportal.u-strasbg.fr\/?target=$value","display":"text","text":"$value","icon":"fas fa-link","blank":true},"detail_display":70,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":1,"id_output_category":4,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute +curl -d '{"id":8,"name":"fits_file","label":"fits_file","form_label":"fits_file","description":null,"primary_key":false,"output_display":80,"criteria_display":80,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"download","renderer_config":{"display":"icon-button","text":"DOWNLOAD","icon":"fas fa-download"},"detail_display":80,"selected":true,"order_by":false,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":4,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute +curl -d '{"id":9,"name":"fits_png","label":"fits_png","form_label":"fits_png","description":null,"primary_key":false,"output_display":90,"criteria_display":90,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"image","renderer_config":{"type":"fits","display":"modal","width":"50","height":"50"},"detail_display":90,"selected":true,"order_by":false,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":4,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/attribute + +# Add observations detail config +curl -d '{"enabled":true,"content":"<div class=\"row justify-content-center\">\n <div class=\"col col-lg-10 col-xl-8 mt-4\">\n <div class=\"row\">\n <div class=\"col-12\">\n <app-display-ra-dec\n [object]=\"context.object\"\n [attributeList]=\"context.attributeList\"\n [attributeRaId]=\"2\"\n [attributeDecId]=\"3\">\n </app-display-ra-dec>\n </div>\n </div>\n\n <app-display-object \n [object]=\"context.object\"\n [attributeList]=\"context.attributeList\"\n [outputFamilyList]=\"context.outputFamilyList\"\n [outputCategoryList]=\"context.outputCategoryList\">\n </app-display-object>\n </div>\n</div>"}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/observations/detail-config # Add vvds_f02_udeep attributes curl -d '{"label":"Default","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/criteria-family curl -d '{"label":"Default","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/output-family curl -d '{"label":"Default","display":10}' --header 'Content-Type: application/json' -X POST http://localhost/output-family/4/output-category -curl -d '{"id":1,"name":"vvds_ident","label":"vvds_ident","form_label":"vvds_ident","description":null,"primary_key":true,"output_display":10,"criteria_display":10,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":10,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":5}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute -curl -d '{"id":2,"name":"id_iau","label":"id_iau","form_label":"id_iau","description":null,"primary_key":false,"output_display":20,"criteria_display":20,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":20,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":5}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute -curl -d '{"id":3,"name":"alpha","label":"alpha","form_label":"alpha","description":null,"primary_key":false,"output_display":30,"criteria_display":30,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":30,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":5}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute -curl -d '{"id":4,"name":"delta","label":"delta","form_label":"delta","description":null,"primary_key":false,"output_display":40,"criteria_display":40,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":40,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":5}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute -curl -d '{"id":5,"name":"z_spec","label":"z_spec","form_label":"z_spec","description":null,"primary_key":false,"output_display":50,"criteria_display":50,"search_type":"between","type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":50,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":4,"id_output_category":5}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute -curl -d '{"id":6,"name":"zflag","label":"zflag","form_label":"zflag","description":null,"primary_key":false,"output_display":60,"criteria_display":60,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":60,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":5}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute -curl -d '{"id":7,"name":"sel_mag","label":"sel_mag","form_label":"sel_mag","description":null,"primary_key":false,"output_display":70,"criteria_display":70,"search_type":"between","type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"display_detail":70,"selected":true,"order_by":true,"archive":false,"detail":false,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":4,"id_output_category":5}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute +curl -d '{"id":1,"name":"vvds_ident","label":"vvds_ident","form_label":"vvds_ident","description":null,"primary_key":true,"output_display":10,"criteria_display":10,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":10,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":5,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute +curl -d '{"id":2,"name":"id_iau","label":"id_iau","form_label":"id_iau","description":null,"primary_key":false,"output_display":20,"criteria_display":20,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":20,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":5,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute +curl -d '{"id":3,"name":"alpha","label":"alpha","form_label":"alpha","description":null,"primary_key":false,"output_display":30,"criteria_display":30,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":30,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":5,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute +curl -d '{"id":4,"name":"delta","label":"delta","form_label":"delta","description":null,"primary_key":false,"output_display":40,"criteria_display":40,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":40,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":5,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute +curl -d '{"id":5,"name":"z_spec","label":"z_spec","form_label":"z_spec","description":null,"primary_key":false,"output_display":50,"criteria_display":50,"search_type":"between","type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":50,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":4,"id_output_category":5,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute +curl -d '{"id":6,"name":"zflag","label":"zflag","form_label":"zflag","description":null,"primary_key":false,"output_display":60,"criteria_display":60,"search_type":null,"type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":60,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":5,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute +curl -d '{"id":7,"name":"sel_mag","label":"sel_mag","form_label":"sel_mag","description":null,"primary_key":false,"output_display":70,"criteria_display":70,"search_type":"between","type":"decimal","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"detail_display":70,"selected":true,"order_by":true,"archive":false,"detail":false,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":4,"id_output_category":5,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/vvds_f02_udeep/attribute # Add products attributes curl -d '{"label":"Obs","display":10,"opened":true}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/criteria-family @@ -94,22 +100,22 @@ curl -d '{"label":"Default","display":10,"opened":true}' --header 'Content-Type: curl -d '{"label":"Default","display":10}' --header 'Content-Type: application/json' -X POST http://localhost/output-family/5/output-category curl -d '{"label":"Additionnal","display":20}' --header 'Content-Type: application/json' -X POST http://localhost/output-family/5/output-category -curl -d '{"id":1,"name":"product_id","label":"product_id","form_label":"Product ID","description":null,"primary_key":true,"output_display":10,"criteria_display":10,"search_type":"field","type":"integer","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":[],"selected":true,"order_by":true,"archive":false,"detail":false,"display_detail":10,"renderer_detail":null,"renderer_detail_config":null,"options":[],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":5,"id_output_category":6}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":2,"name":"obs_id","label":"obs_id","form_label":"Observation ID","description":null,"primary_key":false,"output_display":20,"criteria_display":20,"search_type":"field","type":"bigint","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"display_detail":20,"renderer_detail":null,"renderer_detail_config":null,"options":[],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":5,"id_output_category":6}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":3,"name":"acronym","label":"acronym","form_label":"Product Acronym","description":null,"primary_key":false,"output_display":30,"criteria_display":30,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"display_detail":30,"renderer_detail":null,"renderer_detail_config":null,"options":[{"label":"ECL-DET-UBC","value":"ECL-DET-UBC","display":10},{"label":"OBLC_ECL","value":"OBLC_ECL","display":20}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":6,"id_output_category":6}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":4,"name":"url","label":"url","form_label":"Product URL","description":null,"primary_key":false,"output_display":40,"criteria_display":40,"search_type":null,"type":"text","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"link","renderer_config":{"href":"$value","display":"text","text":"$value","icon":"fas fa-link","blank":true},"selected":true,"order_by":true,"archive":false,"detail":false,"display_detail":40,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":6}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":5,"name":"criteria","label":"criteria","form_label":"Product criteria (based on KWs searchables)","description":null,"primary_key":false,"output_display":50,"criteria_display":50,"search_type":"svom_json_kw","type":"json","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"json","renderer_config":[],"selected":false,"order_by":true,"archive":false,"detail":false,"display_detail":50,"renderer_detail":null,"renderer_detail_config":null,"options":[],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":6,"id_output_category":7}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":6,"name":"added_at","label":"added_at","form_label":"Added at","description":null,"primary_key":false,"output_display":60,"criteria_display":60,"search_type":"between-date","type":"datetime","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"display_detail":60,"renderer_detail":null,"renderer_detail_config":null,"options":[],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":5,"id_output_category":6}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":7,"name":"product_version","label":"product_version","form_label":"Version","description":null,"primary_key":false,"output_display":70,"criteria_display":70,"search_type":null,"type":"integer","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"display_detail":70,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":6}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":8,"name":"program","label":"program","form_label":"Program","description":null,"primary_key":false,"output_display":80,"criteria_display":80,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"display_detail":80,"renderer_detail":null,"renderer_detail_config":null,"options":[{"label":"CoreProgram","value":"CoreProgram","display":10},{"label":"GeneralProgram","value":"GeneralProgram","display":20}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":6,"id_output_category":7}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":9,"name":"instrument","label":"instrument","form_label":"Instrument","description":null,"primary_key":false,"output_display":90,"criteria_display":90,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"display_detail":90,"renderer_detail":null,"renderer_detail_config":null,"options":[{"label":"ECL","value":"ECL","display":10}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":6,"id_output_category":7}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":10,"name":"type","label":"type","form_label":"Type","description":null,"primary_key":false,"output_display":100,"criteria_display":100,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"display_detail":100,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":7}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":11,"name":"upload_filename","label":"upload_filename","form_label":"Filename","description":null,"primary_key":false,"output_display":110,"criteria_display":110,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"display_detail":110,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":6}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":12,"name":"burst_id","label":"burst_id","form_label":"Burst ID","description":null,"primary_key":false,"output_display":120,"criteria_display":120,"search_type":"field","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"display_detail":120,"renderer_detail":null,"renderer_detail_config":null,"options":[],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":5,"id_output_category":6}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":13,"name":"pipeline_version","label":"pipeline_version","form_label":"Pipeline version","description":null,"primary_key":false,"output_display":130,"criteria_display":130,"search_type":null,"type":"float","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"display_detail":130,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":7}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":14,"name":"schema_version","label":"schema_version","form_label":"Schema version","description":null,"primary_key":false,"output_display":140,"criteria_display":140,"search_type":null,"type":"float","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"display_detail":140,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":7}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute -curl -d '{"id":15,"name":"src_id","label":"src_id","form_label":"SRC ID","description":null,"primary_key":false,"output_display":150,"criteria_display":150,"search_type":null,"type":"integer","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"display_detail":150,"renderer_detail":null,"renderer_detail_config":null,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":7}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":1,"name":"product_id","label":"product_id","form_label":"Product ID","description":null,"primary_key":true,"output_display":10,"criteria_display":10,"search_type":"field","type":"integer","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":[],"selected":true,"order_by":true,"archive":false,"detail":false,"detail_display":10,"options":[],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":5,"id_output_category":6,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":2,"name":"obs_id","label":"obs_id","form_label":"Observation ID","description":null,"primary_key":false,"output_display":20,"criteria_display":20,"search_type":"field","type":"bigint","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"detail_display":20,"options":[],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":5,"id_output_category":6,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":3,"name":"acronym","label":"acronym","form_label":"Product Acronym","description":null,"primary_key":false,"output_display":30,"criteria_display":30,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"detail_display":30,"options":[{"label":"ECL-DET-UBC","value":"ECL-DET-UBC","display":10},{"label":"OBLC_ECL","value":"OBLC_ECL","display":20}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":6,"id_output_category":6,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":4,"name":"url","label":"url","form_label":"Product URL","description":null,"primary_key":false,"output_display":40,"criteria_display":40,"search_type":null,"type":"text","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"link","renderer_config":{"href":"$value","display":"text","text":"$value","icon":"fas fa-link","blank":true},"selected":true,"order_by":true,"archive":false,"detail":false,"detail_display":40,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":6,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":5,"name":"criteria","label":"criteria","form_label":"Product criteria (based on KWs searchables)","description":null,"primary_key":false,"output_display":50,"criteria_display":50,"search_type":"svom_json_kw","type":"json","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":"json","renderer_config":[],"selected":false,"order_by":true,"archive":false,"detail":false,"detail_display":50,"options":[],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":6,"id_output_category":7,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":6,"name":"added_at","label":"added_at","form_label":"Added at","description":null,"primary_key":false,"output_display":60,"criteria_display":60,"search_type":"between-date","type":"datetime","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"detail_display":60,"options":[],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":5,"id_output_category":6,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":7,"name":"product_version","label":"product_version","form_label":"Version","description":null,"primary_key":false,"output_display":70,"criteria_display":70,"search_type":null,"type":"integer","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"detail_display":70,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":6,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":8,"name":"program","label":"program","form_label":"Program","description":null,"primary_key":false,"output_display":80,"criteria_display":80,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"detail_display":80,"options":[{"label":"CoreProgram","value":"CoreProgram","display":10},{"label":"GeneralProgram","value":"GeneralProgram","display":20}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":6,"id_output_category":7,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":9,"name":"instrument","label":"instrument","form_label":"Instrument","description":null,"primary_key":false,"output_display":90,"criteria_display":90,"search_type":"select","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"detail_display":90,"options":[{"label":"ECL","value":"ECL","display":10}],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":6,"id_output_category":7,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":10,"name":"type","label":"type","form_label":"Type","description":null,"primary_key":false,"output_display":100,"criteria_display":100,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"detail_display":100,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":7,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":11,"name":"upload_filename","label":"upload_filename","form_label":"Filename","description":null,"primary_key":false,"output_display":110,"criteria_display":110,"search_type":null,"type":"string","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"detail_display":110,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":6,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":12,"name":"burst_id","label":"burst_id","form_label":"Burst ID","description":null,"primary_key":false,"output_display":120,"criteria_display":120,"search_type":"field","type":"string","operator":"eq","dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":true,"order_by":true,"archive":false,"detail":false,"detail_display":120,"options":[],"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":5,"id_output_category":6,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":13,"name":"pipeline_version","label":"pipeline_version","form_label":"Pipeline version","description":null,"primary_key":false,"output_display":130,"criteria_display":130,"search_type":null,"type":"float","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"detail_display":130,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":7,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":14,"name":"schema_version","label":"schema_version","form_label":"Schema version","description":null,"primary_key":false,"output_display":140,"criteria_display":140,"search_type":null,"type":"float","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"detail_display":140,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":7,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute +curl -d '{"id":15,"name":"src_id","label":"src_id","form_label":"SRC ID","description":null,"primary_key":false,"output_display":150,"criteria_display":150,"search_type":null,"type":"integer","operator":null,"dynamic_operator":true,"min":null,"max":null,"placeholder_min":null,"placeholder_max":null,"renderer":null,"renderer_config":null,"selected":false,"order_by":true,"archive":false,"detail":false,"detail_display":150,"options":null,"vo_utype":null,"vo_ucd":null,"vo_unit":null,"vo_description":null,"vo_datatype":null,"vo_size":null,"id_criteria_family":null,"id_output_category":7,"id_detail_output_category":null}' --header 'Content-Type: application/json' -X POST http://localhost/dataset/products/attribute # Add webpages curl -d '{"label":"Default","icon":null,"display":10}' --header 'Content-Type: application/json' -X POST http://localhost/instance/default/webpage-family -curl -d '{"label":"Home","icon":"fas fa-home","display":10,"title":"Home","content":"<div class=\"row align-items-center jumbotron\"><div class=\"col-6 col-md-4 order-md-2 mx-auto text-center\"><img class=\"img-fluid mb-3 mb-md-0\" src=\"http://localhost:8080/instance/default/file-explorer/home_component_logo.png\" alt=\"Instance logo\"></div><div class=\"col-md-8 order-md-1 text-justify pr-md-5\"><h2 class=\"mb-3\">Welcome to the ANIS default instance</h2><p class=\"lead\">This service provides several sub-services to interact with the database.<br>Here is a brief presentation of these sub-services:</p><ul class=\"lead\"><li><a href=\"https://drf-gitlab.cea.fr/svom/sdb/api-import/-/wikis/home\">/import/</a> => This sub-service allows you to import data L0, L1 or SR3/SR4</li><li>/export-rest => => This sub-service allows you to request and export data from the database in json format with a specific URL. To build this URL you could <a class=\"btn btn-warning\" href=\"../../search\">Go to search form</a></li></ul></div></div>"}' --header 'Content-Type: application/json' -X POST http://localhost/webpage-family/1/webpage +curl -d '{"label":"Home","icon":"fas fa-home","display":10,"title":"Home","content":"<div class=\"row align-items-center jumbotron\">\n <div class=\"col-6 col-md-4 order-md-2 mx-auto text-center\">\n <img class=\"img-fluid mb-3 mb-md-0\" src=\"http://localhost:8080/instance/default/file-explorer/home_component_logo.png\" alt=\"Instance logo\">\n </div>\n <div class=\"col-md-8 order-md-1 text-justify pr-md-5\">\n <h2 class=\"mb-3\">Welcome to the ANIS default instance</h2>\n <p class=\"lead\">\n This service provides several sub-services to interact with the database.<br>\n Here is a brief presentation of these sub-services:\n </p>\n <ul class=\"lead\">\n <li>\n <a href=\"https://drf-gitlab.cea.fr/svom/sdb/api-import/-/wikis/home\">\n /import/\n </a> => This sub-service allows you to import data L0, L1 or SR3/SR4\n </li>\n <li>\n /export-rest => => This sub-service allows you to request and export data \n from the database in json format with a specific URL. To build this URL you could \n <a class=\"btn btn-warning\" href=\"../../search\">\n Go to search form\n </a>\n </li>\n </ul>\n </div>\n</div>\n<app-dataset-sample\n [datasetName]=\"'\''observations'\''\"\n [sortingColumn]=\"1\"\n [sortingDirection]=\"'\''d'\''\"\n [nbItems]=\"5\">\n</app-dataset-sample>"}' --header 'Content-Type: application/json' -X POST http://localhost/webpage-family/1/webpage diff --git a/server/app/dependencies.php b/server/app/dependencies.php index 102f8df534db10df4d9be0832cc6825ba9449115..598cb47368ce171d294e421bb30fb2e56dac53d3 100644 --- a/server/app/dependencies.php +++ b/server/app/dependencies.php @@ -225,6 +225,10 @@ $container->set('App\Action\ConeSearchConfigAction', function (ContainerInterfac return new App\Action\ConeSearchConfigAction($c->get('em')); }); +$container->set('App\Action\DetailConfigAction', function (ContainerInterface $c) { + return new App\Action\DetailConfigAction($c->get('em')); +}); + $container->set('App\Action\SearchAction', function (ContainerInterface $c) { $anisQueryBuilder = (new App\Search\Query\AnisQueryBuilder()) ->addQueryPart(new App\Search\Query\From()) diff --git a/server/app/routes.php b/server/app/routes.php index 6ad263ef5e6d50fe512d28a1bc4a4b2d12eb97db..73887c502d2cb9eadbc2853ede6d9586a8be09c0 100644 --- a/server/app/routes.php +++ b/server/app/routes.php @@ -75,6 +75,7 @@ $app->group('', function (RouteCollectorProxy $group) { $group->map([OPTIONS, GET, POST], '/dataset/{name}/file', App\Action\FileListAction::class); $group->map([OPTIONS, GET, PUT, DELETE], '/file/{id}', App\Action\FileAction::class); $group->map([OPTIONS, GET, POST, PUT], '/dataset/{name}/cone-search-config', App\Action\ConeSearchConfigAction::class); + $group->map([OPTIONS, GET, POST, PUT], '/dataset/{name}/detail-config', App\Action\DetailConfigAction::class); })->add(new App\Middleware\RouteGuardMiddleware( boolval($container->get(SETTINGS)['token']['enabled']), array(POST, PUT, DELETE), diff --git a/server/doctrine-proxy/__CG__AppEntityAttribute.php b/server/doctrine-proxy/__CG__AppEntityAttribute.php index 0d1ec8c3f3191d037c0be588092fcc82d35c7c35..e9734fb01579e1ab7e3a2421e77fc5e46fd5ea72 100644 --- a/server/doctrine-proxy/__CG__AppEntityAttribute.php +++ b/server/doctrine-proxy/__CG__AppEntityAttribute.php @@ -67,10 +67,10 @@ class Attribute extends \App\Entity\Attribute implements \Doctrine\ORM\Proxy\Pro public function __sleep() { if ($this->__isInitialized__) { - return ['__isInitialized__', 'id', 'dataset', 'name', 'label', 'formLabel', 'description', 'primaryKey', 'type', 'searchType', 'operator', 'dynamicOperator', 'min', 'max', 'options', 'placeholderMin', 'placeholderMax', 'criteriaDisplay', 'outputDisplay', 'selected', 'renderer', 'rendererConfig', 'orderBy', 'archive', 'detail', 'displayDetail', 'rendererDetail', 'rendererDetailConfig', 'voUtype', 'voUcd', 'voUnit', 'voDescription', 'voDatatype', 'voSize', 'criteriaFamily', 'outputCategory']; + return ['__isInitialized__', 'id', 'dataset', 'name', 'label', 'formLabel', 'description', 'primaryKey', 'type', 'searchType', 'operator', 'dynamicOperator', 'min', 'max', 'options', 'placeholderMin', 'placeholderMax', 'criteriaDisplay', 'outputDisplay', 'selected', 'renderer', 'rendererConfig', 'orderBy', 'archive', 'detailDisplay', 'voUtype', 'voUcd', 'voUnit', 'voDescription', 'voDatatype', 'voSize', 'criteriaFamily', 'outputCategory', 'detailOutputCategory']; } - return ['__isInitialized__', 'id', 'dataset', 'name', 'label', 'formLabel', 'description', 'primaryKey', 'type', 'searchType', 'operator', 'dynamicOperator', 'min', 'max', 'options', 'placeholderMin', 'placeholderMax', 'criteriaDisplay', 'outputDisplay', 'selected', 'renderer', 'rendererConfig', 'orderBy', 'archive', 'detail', 'displayDetail', 'rendererDetail', 'rendererDetailConfig', 'voUtype', 'voUcd', 'voUnit', 'voDescription', 'voDatatype', 'voSize', 'criteriaFamily', 'outputCategory']; + return ['__isInitialized__', 'id', 'dataset', 'name', 'label', 'formLabel', 'description', 'primaryKey', 'type', 'searchType', 'operator', 'dynamicOperator', 'min', 'max', 'options', 'placeholderMin', 'placeholderMax', 'criteriaDisplay', 'outputDisplay', 'selected', 'renderer', 'rendererConfig', 'orderBy', 'archive', 'detailDisplay', 'voUtype', 'voUcd', 'voUnit', 'voDescription', 'voDatatype', 'voSize', 'criteriaFamily', 'outputCategory', 'detailOutputCategory']; } /** @@ -679,23 +679,23 @@ class Attribute extends \App\Entity\Attribute implements \Doctrine\ORM\Proxy\Pro /** * {@inheritDoc} */ - public function getDisplayDetail() + public function getDetailDisplay() { - $this->__initializer__ && $this->__initializer__->__invoke($this, 'getDisplayDetail', []); + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getDetailDisplay', []); - return parent::getDisplayDetail(); + return parent::getDetailDisplay(); } /** * {@inheritDoc} */ - public function setDisplayDetail($displayDetail) + public function setDetailDisplay($detailDisplay) { - $this->__initializer__ && $this->__initializer__->__invoke($this, 'setDisplayDetail', [$displayDetail]); + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setDetailDisplay', [$detailDisplay]); - return parent::setDisplayDetail($displayDetail); + return parent::setDetailDisplay($detailDisplay); } /** @@ -833,111 +833,67 @@ class Attribute extends \App\Entity\Attribute implements \Doctrine\ORM\Proxy\Pro /** * {@inheritDoc} */ - public function getDetail() - { - - $this->__initializer__ && $this->__initializer__->__invoke($this, 'getDetail', []); - - return parent::getDetail(); - } - - /** - * {@inheritDoc} - */ - public function setDetail($detail) - { - - $this->__initializer__ && $this->__initializer__->__invoke($this, 'setDetail', [$detail]); - - return parent::setDetail($detail); - } - - /** - * {@inheritDoc} - */ - public function getRendererDetail() - { - - $this->__initializer__ && $this->__initializer__->__invoke($this, 'getRendererDetail', []); - - return parent::getRendererDetail(); - } - - /** - * {@inheritDoc} - */ - public function setRendererDetail($rendererDetail) - { - - $this->__initializer__ && $this->__initializer__->__invoke($this, 'setRendererDetail', [$rendererDetail]); - - return parent::setRendererDetail($rendererDetail); - } - - /** - * {@inheritDoc} - */ - public function getRendererDetailConfig() + public function getCriteriaFamily() { - $this->__initializer__ && $this->__initializer__->__invoke($this, 'getRendererDetailConfig', []); + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getCriteriaFamily', []); - return parent::getRendererDetailConfig(); + return parent::getCriteriaFamily(); } /** * {@inheritDoc} */ - public function setRendererDetailConfig($rendererDetailConfig) + public function setCriteriaFamily($criteriaFamily) { - $this->__initializer__ && $this->__initializer__->__invoke($this, 'setRendererDetailConfig', [$rendererDetailConfig]); + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setCriteriaFamily', [$criteriaFamily]); - return parent::setRendererDetailConfig($rendererDetailConfig); + return parent::setCriteriaFamily($criteriaFamily); } /** * {@inheritDoc} */ - public function getCriteriaFamily() + public function getOutputCategory() { - $this->__initializer__ && $this->__initializer__->__invoke($this, 'getCriteriaFamily', []); + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getOutputCategory', []); - return parent::getCriteriaFamily(); + return parent::getOutputCategory(); } /** * {@inheritDoc} */ - public function setCriteriaFamily($criteriaFamily) + public function setOutputCategory($outputCategory) { - $this->__initializer__ && $this->__initializer__->__invoke($this, 'setCriteriaFamily', [$criteriaFamily]); + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setOutputCategory', [$outputCategory]); - return parent::setCriteriaFamily($criteriaFamily); + return parent::setOutputCategory($outputCategory); } /** * {@inheritDoc} */ - public function getOutputCategory() + public function getDetailOutputCategory() { - $this->__initializer__ && $this->__initializer__->__invoke($this, 'getOutputCategory', []); + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getDetailOutputCategory', []); - return parent::getOutputCategory(); + return parent::getDetailOutputCategory(); } /** * {@inheritDoc} */ - public function setOutputCategory($outputCategory) + public function setDetailOutputCategory($detailOutputCategory) { - $this->__initializer__ && $this->__initializer__->__invoke($this, 'setOutputCategory', [$outputCategory]); + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setDetailOutputCategory', [$detailOutputCategory]); - return parent::setOutputCategory($outputCategory); + return parent::setDetailOutputCategory($detailOutputCategory); } /** diff --git a/server/doctrine-proxy/__CG__AppEntityDataset.php b/server/doctrine-proxy/__CG__AppEntityDataset.php index 2d0da202673c348e3d21db33c676cf70dcea3e08..cd70caa3d43ccacd978ec065e1107a21206eddf1 100644 --- a/server/doctrine-proxy/__CG__AppEntityDataset.php +++ b/server/doctrine-proxy/__CG__AppEntityDataset.php @@ -67,10 +67,10 @@ class Dataset extends \App\Entity\Dataset implements \Doctrine\ORM\Proxy\Proxy public function __sleep() { if ($this->__isInitialized__) { - return ['__isInitialized__', 'name', 'tableRef', 'label', 'description', 'display', 'dataPath', 'public', 'downloadJson', 'downloadCsv', 'downloadAscii', 'downloadVo', 'serverLinkEnabled', 'datatableEnabled', 'datatableSelectableRows', '' . "\0" . 'App\\Entity\\Dataset' . "\0" . 'coneSearchConfig', 'database', 'datasetFamily', 'attributes']; + return ['__isInitialized__', 'name', 'tableRef', 'label', 'description', 'display', 'dataPath', 'public', 'downloadJson', 'downloadCsv', 'downloadAscii', 'downloadVo', 'serverLinkEnabled', 'datatableEnabled', 'datatableSelectableRows', '' . "\0" . 'App\\Entity\\Dataset' . "\0" . 'coneSearchConfig', '' . "\0" . 'App\\Entity\\Dataset' . "\0" . 'detailConfig', 'database', 'datasetFamily', 'attributes']; } - return ['__isInitialized__', 'name', 'tableRef', 'label', 'description', 'display', 'dataPath', 'public', 'downloadJson', 'downloadCsv', 'downloadAscii', 'downloadVo', 'serverLinkEnabled', 'datatableEnabled', 'datatableSelectableRows', '' . "\0" . 'App\\Entity\\Dataset' . "\0" . 'coneSearchConfig', 'database', 'datasetFamily', 'attributes']; + return ['__isInitialized__', 'name', 'tableRef', 'label', 'description', 'display', 'dataPath', 'public', 'downloadJson', 'downloadCsv', 'downloadAscii', 'downloadVo', 'serverLinkEnabled', 'datatableEnabled', 'datatableSelectableRows', '' . "\0" . 'App\\Entity\\Dataset' . "\0" . 'coneSearchConfig', '' . "\0" . 'App\\Entity\\Dataset' . "\0" . 'detailConfig', 'database', 'datasetFamily', 'attributes']; } /** @@ -500,6 +500,28 @@ class Dataset extends \App\Entity\Dataset implements \Doctrine\ORM\Proxy\Proxy return parent::setConeSearchConfig($coneSearchConfig); } + /** + * {@inheritDoc} + */ + public function getDetailConfig() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getDetailConfig', []); + + return parent::getDetailConfig(); + } + + /** + * {@inheritDoc} + */ + public function setDetailConfig($detailConfig) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setDetailConfig', [$detailConfig]); + + return parent::setDetailConfig($detailConfig); + } + /** * {@inheritDoc} */ diff --git a/server/doctrine-proxy/__CG__AppEntityDetailConfig.php b/server/doctrine-proxy/__CG__AppEntityDetailConfig.php new file mode 100644 index 0000000000000000000000000000000000000000..45fb9beb72f23dc4407d16a627f62218b360833b --- /dev/null +++ b/server/doctrine-proxy/__CG__AppEntityDetailConfig.php @@ -0,0 +1,250 @@ +<?php + +namespace DoctrineProxies\__CG__\App\Entity; + + +/** + * DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE'S PROXY GENERATOR + */ +class DetailConfig extends \App\Entity\DetailConfig implements \Doctrine\ORM\Proxy\Proxy +{ + /** + * @var \Closure the callback responsible for loading properties in the proxy object. This callback is called with + * three parameters, being respectively the proxy object to be initialized, the method that triggered the + * initialization process and an array of ordered parameters that were passed to that method. + * + * @see \Doctrine\Common\Proxy\Proxy::__setInitializer + */ + public $__initializer__; + + /** + * @var \Closure the callback responsible of loading properties that need to be copied in the cloned object + * + * @see \Doctrine\Common\Proxy\Proxy::__setCloner + */ + public $__cloner__; + + /** + * @var boolean flag indicating if this object was already initialized + * + * @see \Doctrine\Persistence\Proxy::__isInitialized + */ + public $__isInitialized__ = false; + + /** + * @var array<string, null> properties to be lazy loaded, indexed by property name + */ + public static $lazyPropertiesNames = array ( +); + + /** + * @var array<string, mixed> default values of properties to be lazy loaded, with keys being the property names + * + * @see \Doctrine\Common\Proxy\Proxy::__getLazyProperties + */ + public static $lazyPropertiesDefaults = array ( +); + + + + public function __construct(?\Closure $initializer = null, ?\Closure $cloner = null) + { + + $this->__initializer__ = $initializer; + $this->__cloner__ = $cloner; + } + + + + + + + + /** + * + * @return array + */ + public function __sleep() + { + if ($this->__isInitialized__) { + return ['__isInitialized__', 'id', 'enabled', 'content']; + } + + return ['__isInitialized__', 'id', 'enabled', 'content']; + } + + /** + * + */ + public function __wakeup() + { + if ( ! $this->__isInitialized__) { + $this->__initializer__ = function (DetailConfig $proxy) { + $proxy->__setInitializer(null); + $proxy->__setCloner(null); + + $existingProperties = get_object_vars($proxy); + + foreach ($proxy::$lazyPropertiesDefaults as $property => $defaultValue) { + if ( ! array_key_exists($property, $existingProperties)) { + $proxy->$property = $defaultValue; + } + } + }; + + } + } + + /** + * + */ + public function __clone() + { + $this->__cloner__ && $this->__cloner__->__invoke($this, '__clone', []); + } + + /** + * Forces initialization of the proxy + */ + public function __load() + { + $this->__initializer__ && $this->__initializer__->__invoke($this, '__load', []); + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __isInitialized() + { + return $this->__isInitialized__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setInitialized($initialized) + { + $this->__isInitialized__ = $initialized; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setInitializer(\Closure $initializer = null) + { + $this->__initializer__ = $initializer; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __getInitializer() + { + return $this->__initializer__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setCloner(\Closure $cloner = null) + { + $this->__cloner__ = $cloner; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific cloning logic + */ + public function __getCloner() + { + return $this->__cloner__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + * @deprecated no longer in use - generated code now relies on internal components rather than generated public API + * @static + */ + public function __getLazyProperties() + { + return self::$lazyPropertiesDefaults; + } + + + /** + * {@inheritDoc} + */ + public function getId() + { + if ($this->__isInitialized__ === false) { + return (int) parent::getId(); + } + + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getId', []); + + return parent::getId(); + } + + /** + * {@inheritDoc} + */ + public function getEnabled() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getEnabled', []); + + return parent::getEnabled(); + } + + /** + * {@inheritDoc} + */ + public function setEnabled($enabled) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setEnabled', [$enabled]); + + return parent::setEnabled($enabled); + } + + /** + * {@inheritDoc} + */ + public function getContent() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getContent', []); + + return parent::getContent(); + } + + /** + * {@inheritDoc} + */ + public function setContent($content) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setContent', [$content]); + + return parent::setContent($content); + } + + /** + * {@inheritDoc} + */ + public function jsonSerialize(): array + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'jsonSerialize', []); + + return parent::jsonSerialize(); + } + +} diff --git a/server/src/Action/AttributeAction.php b/server/src/Action/AttributeAction.php index 75b4cd761646ba7a83a483988647a28d87a76477..4ceb4096c1a7eaf5ba2c3f9d653a3805b0ae9e9e 100644 --- a/server/src/Action/AttributeAction.php +++ b/server/src/Action/AttributeAction.php @@ -85,10 +85,7 @@ final class AttributeAction extends AbstractAction 'renderer_config', 'order_by', 'archive', - 'detail', - 'display_detail', - 'renderer_detail', - 'renderer_detail_config', + 'detail_display', 'vo_utype', 'vo_ucd', 'vo_unit', @@ -96,7 +93,8 @@ final class AttributeAction extends AbstractAction 'vo_datatype', 'vo_size', 'id_criteria_family', - 'id_output_category' + 'id_output_category', + 'id_detail_output_category' ); foreach ($fields as $a) { if (!array_key_exists($a, $parsedBody)) { @@ -152,10 +150,7 @@ final class AttributeAction extends AbstractAction $attribute->setRendererConfig($parsedBody['renderer_config']); $attribute->setOrderBy($parsedBody['order_by']); $attribute->setArchive($parsedBody['archive']); - $attribute->setDetail($parsedBody['detail']); - $attribute->setDisplayDetail($parsedBody['display_detail']); - $attribute->setRendererDetail($parsedBody['renderer_detail']); - $attribute->setRendererDetailConfig($parsedBody['renderer_detail_config']); + $attribute->setDetailDisplay($parsedBody['detail_display']); $attribute->setVoUtype($parsedBody['vo_utype']); $attribute->setVoUcd($parsedBody['vo_ucd']); $attribute->setVoUnit($parsedBody['vo_unit']); @@ -180,6 +175,15 @@ final class AttributeAction extends AbstractAction ); } $attribute->setOutputCategory($outputCategory); + if (is_null($parsedBody['id_detail_output_category'])) { + $detailOutputCategory = null; + } else { + $detailOutputCategory = $this->em->find( + 'App\Entity\OutputCategory', + $parsedBody['id_detail_output_category'] + ); + } + $attribute->setDetailOutputCategory($detailOutputCategory); $this->em->flush(); } } diff --git a/server/src/Action/AttributeListAction.php b/server/src/Action/AttributeListAction.php index b98cae3d873a8401d2341ff816b0c93641b92cd4..e1496b10d00f994be42136fd2cdaaa719a39c80a 100644 --- a/server/src/Action/AttributeListAction.php +++ b/server/src/Action/AttributeListAction.php @@ -87,10 +87,7 @@ final class AttributeListAction extends AbstractAction 'renderer_config', 'order_by', 'archive', - 'detail', - 'display_detail', - 'renderer_detail', - 'renderer_detail_config', + 'detail_display', 'vo_utype', 'vo_ucd', 'vo_unit', @@ -98,7 +95,8 @@ final class AttributeListAction extends AbstractAction 'vo_datatype', 'vo_size', 'id_criteria_family', - 'id_output_category' + 'id_output_category', + 'id_detail_output_category' ); foreach ($fields as $a) { if (!array_key_exists($a, $parsedBody)) { @@ -150,10 +148,7 @@ final class AttributeListAction extends AbstractAction $attribute->setRendererConfig($parsedBody['renderer_config']); $attribute->setOrderBy($parsedBody['order_by']); $attribute->setArchive($parsedBody['archive']); - $attribute->setDetail($parsedBody['detail']); - $attribute->setDisplayDetail($parsedBody['display_detail']); - $attribute->setRendererDetail($parsedBody['renderer_detail']); - $attribute->setRendererDetailConfig($parsedBody['renderer_detail_config']); + $attribute->setDetailDisplay($parsedBody['detail_display']); $attribute->setVoUtype($parsedBody['vo_utype']); $attribute->setVoUcd($parsedBody['vo_ucd']); $attribute->setVoUnit($parsedBody['vo_unit']); @@ -178,6 +173,15 @@ final class AttributeListAction extends AbstractAction ); } $attribute->setOutputCategory($outputCategory); + if (is_null($parsedBody['id_detail_output_category'])) { + $detailOutputCategory = null; + } else { + $detailOutputCategory = $this->em->find( + 'App\Entity\OutputCategory', + $parsedBody['id_detail_output_category'] + ); + } + $attribute->setDetailOutputCategory($detailOutputCategory); $this->em->persist($attribute); $this->em->flush(); diff --git a/server/src/Action/DetailConfigAction.php b/server/src/Action/DetailConfigAction.php new file mode 100644 index 0000000000000000000000000000000000000000..38877b680c223c67f67ce097096cb457c3a2027f --- /dev/null +++ b/server/src/Action/DetailConfigAction.php @@ -0,0 +1,154 @@ +<?php + +/* + * This file is part of Anis Server. + * + * (c) 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. + */ +declare(strict_types=1); + +namespace App\Action; + +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; +use Slim\Exception\HttpBadRequestException; +use Slim\Exception\HttpNotFoundException; +use App\Entity\DetailConfig; +use App\Entity\Dataset; + +/** + * @author François Agneray <francois.agneray@lam.fr> + * @package App\Action + */ +final class DetailConfigAction extends AbstractAction +{ + /** + * `GET` Returns the detail configuration found + * `PUT` Full update the detail configuration and returns the new version + * `DELETE` Delete the detail configuration and return a confirmation message + * + * @param ServerRequestInterface $request PSR-7 This object represents the HTTP request + * @param ResponseInterface $response PSR-7 This object represents the HTTP response + * @param string[] $args This table contains information transmitted in the URL (see routes.php) + * + * @return ResponseInterface + */ + public function __invoke( + ServerRequestInterface $request, + ResponseInterface $response, + array $args + ): ResponseInterface { + if ($request->getMethod() === OPTIONS) { + return $response->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS'); + } + + $dataset = $this->em->find('App\Entity\Dataset', $args['name']); + + // Returns HTTP 404 if the dataset is not found + if (is_null($dataset)) { + throw new HttpNotFoundException( + $request, + 'Dataset with name ' . $args['name'] . ' is not found' + ); + } + + // Search the correct detail configuration with primary key + if ($dataset->getDetailConfig()) { + $detailConfig = $this->em->find( + 'App\Entity\DetailConfig', + $dataset->getDetailConfig()->getId() + ); + } else { + $detailConfig = null; + } + + if ($request->getMethod() === GET) { + $payload = json_encode($detailConfig); + } + + if ($request->getMethod() === POST) { + $parsedBody = $request->getParsedBody(); + $this->checkParsedBody($parsedBody, $request); + $detailConfig = $this->postDetailConfig($parsedBody, $dataset); + $payload = json_encode($detailConfig); + $response = $response->withStatus(201); + } + + if ($request->getMethod() === PUT) { + // Returns HTTP 404 if the detail configuation is not found + if (is_null($detailConfig)) { + throw new HttpNotFoundException( + $request, + 'Detail config is not found' + ); + } + + $parsedBody = $request->getParsedBody(); + $this->checkParsedBody($parsedBody, $request); + + $this->editDetailConfig($detailConfig, $parsedBody); + $payload = json_encode($detailConfig); + } + + $response->getBody()->write($payload); + return $response; + } + + /** + * @param array $parsedBody Contains the values ​​of the new detail configuration + * @param ServerRequestInterface $request PSR-7 This object represents the HTTP request + */ + private function checkParsedBody($parsedBody, $request) + { + $fields = array( + 'enabled', + 'content' + ); + + // To work this actions needs information + foreach ($fields as $a) { + if (!array_key_exists($a, $parsedBody)) { + throw new HttpBadRequestException( + $request, + 'Param ' . $a . ' needed to add or edit detail configuration' + ); + } + } + } + + /** + * @param array $parsedBody Contains the values ​​of the new detail configuration sent by the user + * @param Dataset $dataset Dataset for adding the detail configuration + * + * @return DetailConfig + */ + private function postDetailConfig(array $parsedBody, Dataset $dataset): DetailConfig + { + $detailConfig = new DetailConfig(); + $detailConfig->setEnabled($parsedBody['enabled']); + $detailConfig->setContent($parsedBody['content']); + + $dataset->setDetailConfig($detailConfig); + + $this->em->persist($dataset); + $this->em->flush(); + + return $detailConfig; + } + + /** + * Update detail configuration object with setters + * + * @param DetailConfig $detailConfig The detail configuration to update + * @param string[] $parsedBody Contains the new values ​​of the detail sent by the user + */ + private function editDetailConfig(detailConfig $detailConfig, array $parsedBody): void + { + $detailConfig->setEnabled($parsedBody['enabled']); + $detailConfig->setContent($parsedBody['content']); + $this->em->flush(); + } +} diff --git a/server/src/Entity/Attribute.php b/server/src/Entity/Attribute.php index ffe7b3ba5ea6912bdc535427bd10c9ef6594693a..82f8aeb5d389af1631b9c39ae6d0b92cd429e087 100644 --- a/server/src/Entity/Attribute.php +++ b/server/src/Entity/Attribute.php @@ -185,33 +185,12 @@ class Attribute implements \JsonSerializable */ protected $archive; - /** - * @var bool - * - * @Column(type="boolean", name="detail", nullable=false, options={"default":false}) - */ - protected $detail; - /** * @var int * - * @Column(type="integer", name="display_detail", nullable=true) - */ - protected $displayDetail; - - /** - * @var string - * - * @Column(type="string", name="renderer_detail", nullable=true) + * @Column(type="integer", name="detail_display", nullable=true) */ - protected $rendererDetail; - - /** - * @var string - * - * @Column(type="json", name="renderer_detail_config", nullable=true) - */ - protected $rendererDetailConfig; + protected $detailDisplay; /** * @var string @@ -271,6 +250,14 @@ class Attribute implements \JsonSerializable */ protected $outputCategory; + /** + * @var OutputCategory + * + * @ManyToOne(targetEntity="OutputCategory") + * @JoinColumn(name="detail_output_category", referencedColumnName="id", nullable=true, onDelete="SET NULL") + */ + protected $detailOutputCategory; + public function __construct(int $id, Dataset $dataset) { $this->id = $id; @@ -502,14 +489,14 @@ class Attribute implements \JsonSerializable $this->archive = $archive; } - public function getDisplayDetail() + public function getDetailDisplay() { - return $this->displayDetail; + return $this->detailDisplay; } - public function setDisplayDetail($displayDetail) + public function setDetailDisplay($detailDisplay) { - $this->displayDetail = $displayDetail; + $this->detailDisplay = $detailDisplay; } public function getVoUtype() @@ -572,36 +559,6 @@ class Attribute implements \JsonSerializable $this->voSize = $voSize; } - public function getDetail() - { - return $this->detail; - } - - public function setDetail($detail) - { - $this->detail = $detail; - } - - public function getRendererDetail() - { - return $this->rendererDetail; - } - - public function setRendererDetail($rendererDetail) - { - $this->rendererDetail = $rendererDetail; - } - - public function getRendererDetailConfig() - { - return $this->rendererDetailConfig; - } - - public function setRendererDetailConfig($rendererDetailConfig) - { - $this->rendererDetailConfig = $rendererDetailConfig; - } - public function getCriteriaFamily() { return $this->criteriaFamily; @@ -622,6 +579,16 @@ class Attribute implements \JsonSerializable $this->outputCategory = $outputCategory; } + public function getDetailOutputCategory() + { + return $this->detailOutputCategory; + } + + public function setDetailOutputCategory($detailOutputCategory) + { + $this->detailOutputCategory = $detailOutputCategory; + } + public function jsonSerialize(): array { return [ @@ -647,10 +614,7 @@ class Attribute implements \JsonSerializable 'renderer_config' => $this->getRendererConfig(), 'order_by' => $this->getOrderBy(), 'archive' => $this->getArchive(), - 'detail' => $this->getDetail(), - 'display_detail' => $this->getDisplayDetail(), - 'renderer_detail' => $this->getRendererDetail(), - 'renderer_detail_config' => $this->getRendererDetailConfig(), + 'detail_display' => $this->getDetailDisplay(), 'vo_utype' => $this->getVoUtype(), 'vo_ucd' => $this->getVoUcd(), 'vo_unit' => $this->getVoUnit(), @@ -658,7 +622,8 @@ class Attribute implements \JsonSerializable 'vo_datatype' => $this->getVoDatatype(), 'vo_size' => $this->getVoSize(), 'id_criteria_family' => is_null($this->getCriteriaFamily()) ? null : $this->getCriteriaFamily()->getId(), - 'id_output_category' => is_null($this->getOutputCategory()) ? null : $this->getOutputCategory()->getId() + 'id_output_category' => is_null($this->getOutputCategory()) ? null : $this->getOutputCategory()->getId(), + 'id_detail_output_category' => is_null($this->getDetailOutputCategory()) ? null : $this->getDetailOutputCategory()->getId() ]; } } diff --git a/server/src/Entity/Dataset.php b/server/src/Entity/Dataset.php index 5fb2e20b3891e9c501c01a7e994301ebf858464b..9edf396e1ea072970550094dffbb6e78f2c68d4f 100644 --- a/server/src/Entity/Dataset.php +++ b/server/src/Entity/Dataset.php @@ -130,6 +130,14 @@ class Dataset implements \JsonSerializable */ private $coneSearchConfig; + /** + * @var DetailConfig + * + * @OneToOne(targetEntity="DetailConfig", cascade={"persist", "remove"}) + * @JoinColumn(name="detail_config_id", referencedColumnName="id", nullable=true) + */ + private $detailConfig; + /** * @var Database * @@ -304,6 +312,16 @@ class Dataset implements \JsonSerializable $this->coneSearchConfig = $coneSearchConfig; } + public function getDetailConfig() + { + return $this->detailConfig; + } + + public function setDetailConfig($detailConfig) + { + $this->detailConfig = $detailConfig; + } + public function setDatabase($database) { $this->database = $database; @@ -353,6 +371,8 @@ class Dataset implements \JsonSerializable 'datatable_selectable_rows' => $this->getDatatableSelectableRows(), 'cone_search_config_id' => is_null($this->getConeSearchConfig()) ? null : $this->getConeSearchConfig()->getId(), + 'detail_config_id' => is_null($this->getDetailConfig()) + ? null : $this->getDetailConfig()->getId(), 'id_database' => $this->getDatabase()->getId(), 'id_dataset_family' => $this->getDatasetFamily()->getId(), 'full_data_path' => $this->getFullDataPath() diff --git a/server/src/Entity/DetailConfig.php b/server/src/Entity/DetailConfig.php new file mode 100644 index 0000000000000000000000000000000000000000..768e3ee18eacf7223cf5dd07373bed8c8e8300ef --- /dev/null +++ b/server/src/Entity/DetailConfig.php @@ -0,0 +1,80 @@ +<?php + +/* + * This file is part of Anis Server. + * + * (c) 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. + */ +declare(strict_types=1); + +namespace App\Entity; + +/** + * @author François Agneray <francois.agneray@lam.fr> + * @package App\Entity + * + * @Entity + * @Table(name="detail") + */ +class DetailConfig implements \JsonSerializable +{ + /** + * @var int + * + * @Id + * @Column(type="integer", nullable=false) + * @GeneratedValue + */ + protected $id; + + /** + * @var bool + * + * @Column(type="boolean", name="enabled", nullable=false) + */ + protected $enabled; + + /** + * @var string + * + * @Column(type="text", name="content", nullable=false) + */ + protected $content; + + public function getId() + { + return $this->id; + } + + public function getEnabled() + { + return $this->enabled; + } + + public function setEnabled($enabled) + { + $this->enabled = $enabled; + } + + public function getContent() + { + return $this->content; + } + + public function setContent($content) + { + $this->content = $content; + } + + public function jsonSerialize(): array + { + return [ + 'id' => $this->getId(), + 'enabled' => $this->getEnabled(), + 'content' => $this->getContent() + ]; + } +} diff --git a/server/tests/Action/AttributeActionTest.php b/server/tests/Action/AttributeActionTest.php index a9de89c31cf8c8e8b32dd69a95e9244f09fa8d1e..0617eb9516e2ebe7017146203d99d8a29b93a1be 100644 --- a/server/tests/Action/AttributeActionTest.php +++ b/server/tests/Action/AttributeActionTest.php @@ -152,9 +152,7 @@ final class AttributeActionTest extends TestCase 'order_by' => false, 'archive' => false, 'detail' => false, - 'display_detail' => 10, - 'renderer_detail' => null, - 'renderer_detail_config' => null, + 'detail_display' => 10, 'vo_utype' => null, 'vo_ucd' => null, 'vo_unit' => null, @@ -162,7 +160,8 @@ final class AttributeActionTest extends TestCase 'vo_datatype' => null, 'vo_size' => 0, 'id_criteria_family' => 1, - 'id_output_category' => 1 + 'id_output_category' => 1, + 'id_detail_output_category' => null ); } diff --git a/server/tests/Action/AttributeListActionTest.php b/server/tests/Action/AttributeListActionTest.php index 1dcce595519470ea4db572440e833d4430da674c..85e3368ace16c9107f8272c884c4b2e73ff43a63 100644 --- a/server/tests/Action/AttributeListActionTest.php +++ b/server/tests/Action/AttributeListActionTest.php @@ -104,9 +104,7 @@ final class AttributeListActionTest extends TestCase 'order_by' => false, 'archive' => false, 'detail' => false, - 'display_detail' => 10, - 'renderer_detail' => null, - 'renderer_detail_config' => null, + 'detail_display' => 10, 'vo_utype' => null, 'vo_ucd' => null, 'vo_unit' => null, @@ -114,7 +112,8 @@ final class AttributeListActionTest extends TestCase 'vo_datatype' => null, 'vo_size' => 0, 'id_criteria_family' => null, - 'id_output_category' => null + 'id_output_category' => null, + 'id_detail_output_category' => null ); $this->entityManager->expects($this->once())->method('persist');