diff --git a/client/src/app/instance/search/components/criteria/criterion.component.html b/client/src/app/instance/search/components/criteria/criterion.component.html index 7099c3eca20a103bcd7aee65fe712fd78c32dec9..f9249c619b86339377989b806c7bef02cf295fea 100644 --- a/client/src/app/instance/search/components/criteria/criterion.component.html +++ b/client/src/app/instance/search/components/criteria/criterion.component.html @@ -1,19 +1,12 @@ <div class="row"> <div class="col form-group"> <label> - <app-attribute-label [label]="attribute.label" [description]="attribute.description"></app-attribute-label> + <app-attribute-label [label]="attribute.form_label" [description]="attribute.description"></app-attribute-label> </label> <ng-template searchType></ng-template> </div> <div class="col-2 text-center align-self-center"> - <select [disabled]="criterion != null" class="form-control" [(ngModel)]="nullOrNotNull" (change)="onChangeNull()"> - <option></option> - <option value="nl">Null</option> - <option value="nnl">Not null</option> - </select> - </div> - <div class="col-2 text-center align-self-center"> - <button class="btn btn-outline-success" *ngIf="!criterion" [hidden]="!searchTypeComponent.isValid() && !nullOrNotNull" (click)="emitAdd()"> + <button class="btn btn-outline-success" *ngIf="!criterion" [hidden]="!searchTypeComponent.isValid() && !searchTypeComponent.nullOrNotNull" (click)="emitAdd()"> <span class="fas fa-plus fa-fw"></span> </button> <button class="btn btn-outline-danger" *ngIf="criterion" (click)="deleteCriterion.emit(attribute.id)"> diff --git a/client/src/app/instance/search/components/criteria/criterion.component.ts b/client/src/app/instance/search/components/criteria/criterion.component.ts index 2e53cd3ddc42747beb12f8c77505badcf7e721b2..245f6fba7466aaba222547c067c764facfa8ad8c 100644 --- a/client/src/app/instance/search/components/criteria/criterion.component.ts +++ b/client/src/app/instance/search/components/criteria/criterion.component.ts @@ -27,7 +27,6 @@ export class CriterionComponent implements OnInit, OnChanges { @ViewChild(SearchTypeLoaderDirective, {static: true}) SearchTypeLoaderDirective!: SearchTypeLoaderDirective; public searchTypeComponent: AbstractSearchTypeComponent; - public nullOrNotNull: string; ngOnInit() { const viewContainerRef = this.SearchTypeLoaderDirective.viewContainerRef; @@ -43,9 +42,6 @@ export class CriterionComponent implements OnInit, OnChanges { ngOnChanges(changes: SimpleChanges): void { if (changes.criterion && !changes.criterion.firstChange) { this.searchTypeComponent.setCriterion(changes.criterion.currentValue); - if (!changes.criterion.currentValue) { - this.nullOrNotNull = ''; - } } if (changes.criteriaList && !changes.criteriaList.firstChange) { @@ -53,14 +49,6 @@ export class CriterionComponent implements OnInit, OnChanges { } } - onChangeNull() { - if (this.nullOrNotNull) { - this.searchTypeComponent.disable(); - } else { - this.searchTypeComponent.enable(); - } - } - /** * Emits event to add criterion to the criteria list. * @@ -68,11 +56,11 @@ export class CriterionComponent implements OnInit, OnChanges { */ emitAdd(): void { let criterion: Criterion; - if (this.nullOrNotNull) { + if (this.searchTypeComponent.nullOrNotNull) { criterion = { id: this.attribute.id, type: 'field', - operator: this.nullOrNotNull + operator: this.searchTypeComponent.nullOrNotNull } as FieldCriterion; } else { criterion = this.searchTypeComponent.getCriterion(); diff --git a/client/src/app/instance/search/components/criteria/index.ts b/client/src/app/instance/search/components/criteria/index.ts index 384fec9fedf22ed74f2127a6d7272fbee81c43df..6a2833b207e45204194a5599100d0acc92eccf39 100644 --- a/client/src/app/instance/search/components/criteria/index.ts +++ b/client/src/app/instance/search/components/criteria/index.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { ConeSearchTabComponent } from './cone-search-tab.component'; import { CriteriaTabsComponent } from './criteria-tabs.component'; import { CriteriaByFamilyComponent } from './criteria-by-family.component'; diff --git a/client/src/app/instance/search/components/criteria/search-type/abstract-search-type.component.ts b/client/src/app/instance/search/components/criteria/search-type/abstract-search-type.component.ts index 8b0febc3b738700a22e886c0f8eae01e994a737f..0d8b4b7b6b6d4f9f272dcd9cf9b99669d30abda5 100644 --- a/client/src/app/instance/search/components/criteria/search-type/abstract-search-type.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/abstract-search-type.component.ts @@ -1,4 +1,13 @@ -import { Directive, Input } from '@angular/core'; +/** + * 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 { Directive } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { Attribute } from 'src/app/metamodel/models'; @@ -12,6 +21,7 @@ export abstract class AbstractSearchTypeComponent { form: FormGroup; operators = searchTypeOperators; + nullOrNotNull: string = ''; constructor() { } @@ -26,6 +36,7 @@ export abstract class AbstractSearchTypeComponent { } else { this.form.enable(); this.form.reset(); + this.nullOrNotNull = ''; } } diff --git a/client/src/app/instance/search/components/criteria/search-type/between-date.component.html b/client/src/app/instance/search/components/criteria/search-type/between-date.component.html index 776a39f64a1a0403874f9de82e1063829b1862f8..8704391594cb241bf3f714629a75a74a594d0108 100644 --- a/client/src/app/instance/search/components/criteria/search-type/between-date.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/between-date.component.html @@ -1,7 +1,9 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-sm-0"> - <div class="operator_readonly">BW</div> + <select class="custom-select" formControlName="label" (change)="labelOnChange()"> + <option *ngFor="let l of labels" [ngValue]="l.value">{{ l.label }}</option> + </select> </div> <div class="w-100 d-block d-sm-none"></div> <div class="col pl-sm-1"> diff --git a/client/src/app/instance/search/components/criteria/search-type/between-date.component.ts b/client/src/app/instance/search/components/criteria/search-type/between-date.component.ts index f90a2cb2d658fda3141dc57cda5bc440bf4e8a9c..2706a27eef6f55c9dff0053da83dc3bdaee10f29 100644 --- a/client/src/app/instance/search/components/criteria/search-type/between-date.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/between-date.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; @@ -9,11 +18,19 @@ import { Criterion, BetweenCriterion } from 'src/app/instance/store/models'; templateUrl: 'between-date.component.html' }) export class BetweenDateComponent extends AbstractSearchTypeComponent { + labels = [ + { value: 'bw', label: 'between' }, + { value: 'nl', label: 'null' }, + { value: 'nnl', label: 'not null' } + ]; + constructor() { super(); this.form = new FormGroup({ + label: new FormControl(), dateRange: new FormControl('', [Validators.required]) }); + } setCriterion(criterion: Criterion) { @@ -24,9 +41,11 @@ export class BetweenDateComponent extends AbstractSearchTypeComponent { new Date(betweenCriterion.min), new Date(betweenCriterion.max) ]); + } else { + this.form.controls.label.setValue('bw'); } } - + /** * Return new criterion * @@ -56,4 +75,13 @@ export class BetweenDateComponent extends AbstractSearchTypeComponent { const day = ('0' + (date.getDate())).slice(-2); return `${date.getFullYear()}-${month}-${day}`; } + + labelOnChange() { + if (this.form.controls.label.value === 'nl' || this.form.controls.label.value === 'nnl') { + this.nullOrNotNull = this.form.controls.label.value; + this.form.controls.dateRange.disable(); + } else { + this.form.controls.dateRange.enable(); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/between.component.html b/client/src/app/instance/search/components/criteria/search-type/between.component.html index d48fcb25a923daf02ddcb59ef13dd2bbcb1d6bc7..945264f656788b31084fda5129b4b4e88328b1c3 100644 --- a/client/src/app/instance/search/components/criteria/search-type/between.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/between.component.html @@ -1,16 +1,16 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-sm-0"> - <div class="operator_readonly">Min</div> + <select class="custom-select" formControlName="label" (change)="labelOnChange()"> + <option *ngFor="let l of labels" [ngValue]="l.value">{{ l.label }}</option> + </select> </div> <div class="w-100 d-block d-sm-none"></div> <div class="col pl-sm-1 mb-1 mb-sm-0"> <input type="text" class="form-control" [placeholder]="getPlaceholderMin()" formControlName="min" autocomplete="off" /> </div> <div class="w-100 d-block d-lg-none"></div> - <div class="col col-sm-3 col-lg-auto pr-sm-1 mb-1"> - <div class="operator_readonly">Max</div> - </div> + <div class="w-100 d-block d-sm-none"></div> <div class="col pl-sm-1"> <input type="text" class="form-control" [placeholder]="getPlaceholderMax()" formControlName="max" autocomplete="off" /> diff --git a/client/src/app/instance/search/components/criteria/search-type/between.component.ts b/client/src/app/instance/search/components/criteria/search-type/between.component.ts index c111105c04db07aedbf6ccda7faacfbb4e386a3c..0aeeb599b2f5c71978cc70aceb221fe837fccd58 100644 --- a/client/src/app/instance/search/components/criteria/search-type/between.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/between.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; @@ -9,14 +18,28 @@ import { Criterion, BetweenCriterion } from 'src/app/instance/store/models'; templateUrl: 'between.component.html' }) export class BetweenComponent extends AbstractSearchTypeComponent { + labels = [ + { value: 'bw', label: 'min/max' }, + { value: 'nl', label: 'null' }, + { value: 'nnl', label: 'not null' } + ]; + constructor() { super(); this.form = new FormGroup({ + label: new FormControl('', [Validators.required]), min: new FormControl('', [Validators.required]), max: new FormControl('', [Validators.required]) }); } + setCriterion(criterion: Criterion): void { + super.setCriterion(criterion); + if (!criterion) { + this.form.controls.label.setValue('bw'); + } + } + /** * Return new criterion * @@ -59,4 +82,15 @@ export class BetweenComponent extends AbstractSearchTypeComponent { isValid() { return this.form.controls.min.value || this.form.controls.max.value; } + + labelOnChange() { + if (this.form.controls.label.value === 'nl' || this.form.controls.label.value === 'nnl') { + this.nullOrNotNull = this.form.controls.label.value; + this.form.controls.min.disable(); + this.form.controls.max.disable(); + } else { + this.form.controls.max.enable(); + this.form.controls.min.enable(); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/checkbox.component.html b/client/src/app/instance/search/components/criteria/search-type/checkbox.component.html index 936cd8786ea93bf2d5c03df2b4c4f0158cfb743b..5ebc32918f042ee6ecd11d2f4ea1f55ece22aba6 100644 --- a/client/src/app/instance/search/components/criteria/search-type/checkbox.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/checkbox.component.html @@ -1,7 +1,9 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-lg-0"> - <div class="operator_readonly">in</div> + <select class="custom-select" formControlName="label" (change)="labelOnChange()"> + <option *ngFor="let l of labels" [ngValue]="l.value">{{ l.label }}</option> + </select> </div> <div class="w-100 d-block d-sm-none"></div> <div class="col pl-sm-1" formArrayName="checkboxes"> diff --git a/client/src/app/instance/search/components/criteria/search-type/checkbox.component.ts b/client/src/app/instance/search/components/criteria/search-type/checkbox.component.ts index 8d9b1b070290fb878fc4a34812982b8464711981..9fe0de55dbb9ff23c08073c4c204cb71b3bda6e7 100644 --- a/client/src/app/instance/search/components/criteria/search-type/checkbox.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/checkbox.component.ts @@ -1,5 +1,14 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; -import { FormGroup, FormControl, FormArray, Validators } from '@angular/forms'; +import { FormGroup, FormControl, FormArray } from '@angular/forms'; import { AbstractSearchTypeComponent } from './abstract-search-type.component'; import { Criterion, SelectMultipleCriterion } from 'src/app/instance/store/models'; @@ -8,12 +17,20 @@ import { Attribute } from 'src/app/metamodel/models'; @Component({ selector: 'app-checkbox', templateUrl: 'checkbox.component.html', - styleUrls: ['checkbox.component.scss' ], + styleUrls: ['checkbox.component.scss'], }) export class CheckboxComponent extends AbstractSearchTypeComponent { + labels = [ + { value: 'in', label: 'in' }, + { value: 'nl', label: 'null' }, + { value: 'nnl', label: 'not null' } + ]; + constructor() { super(); - this.form = new FormGroup({}); + this.form = new FormGroup({ + label: new FormControl('') + }); } setAttribute(attribute: Attribute): void { @@ -28,15 +45,18 @@ export class CheckboxComponent extends AbstractSearchTypeComponent { setCriterion(criterion: Criterion) { super.setCriterion(criterion); + if (criterion) { for (let i = 0; i < this.attribute.options.length; i++) { if ((criterion as SelectMultipleCriterion).options.find(o => o.label === this.attribute.options[i].label)) { this.getCheckboxes().controls[i].setValue(true); } } + } else { + this.form.controls.label.setValue('in'); } } - + /** * Return new criterion * @@ -77,4 +97,17 @@ export class CheckboxComponent extends AbstractSearchTypeComponent { // If one of the checkboxes is checked returns true else returns false return this.getCheckboxes().controls.filter(formControl => formControl.value).length > 0; } + + labelOnChange() { + if (this.form.controls.label.value === 'nl' || this.form.controls.label.value === 'nnl') { + this.nullOrNotNull = this.form.controls.label.value; + this.getCheckboxes().controls.map((value, index) => { + value.disable(); + }); + } else { + this.getCheckboxes().controls.map((value, index) => { + value.enable(); + }); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/datalist.component.html b/client/src/app/instance/search/components/criteria/search-type/datalist.component.html index 0044b68c1fd4e5ed6290d839fa4dd8f3bf8d9873..e0f39d837b2c9ec00d6e42bec28f201d5565abfc 100644 --- a/client/src/app/instance/search/components/criteria/search-type/datalist.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/datalist.component.html @@ -1,7 +1,7 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-sm-0"> - <select class="custom-select" formControlName="operator"> + <select class="custom-select" formControlName="operator" (change)="operatorOnChange()"> <option *ngFor="let o of operators" [ngValue]="o.value">{{ o.label }}</option> </select> </div> diff --git a/client/src/app/instance/search/components/criteria/search-type/datalist.component.ts b/client/src/app/instance/search/components/criteria/search-type/datalist.component.ts index ccbc14a555367f1ed135ce9ab6102e9b87b17076..0ff56c56a87051757e80a54a475647cad8eab706 100644 --- a/client/src/app/instance/search/components/criteria/search-type/datalist.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/datalist.component.ts @@ -1,8 +1,18 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { AbstractSearchTypeComponent } from './abstract-search-type.component'; import { Criterion, FieldCriterion } from 'src/app/instance/store/models'; +import { searchTypeOperators } from 'src/app/shared/utils'; @Component({ selector: 'app-datalist', @@ -22,11 +32,12 @@ export class DatalistComponent extends AbstractSearchTypeComponent { if (!criterion) { this.form.controls.operator.setValue(this.attribute.operator); if (!this.attribute.dynamic_operator) { - this.form.controls.operator.disable(); + this.operators = searchTypeOperators.filter( + operator => [this.attribute.operator, 'nl', 'nnl'].includes(operator.value) + ); } } } - /** * Return new criterion * @@ -72,4 +83,12 @@ export class DatalistComponent extends AbstractSearchTypeComponent { getDatalistId(): string { return `datalist_${this.attribute.id}`; } + + operatorOnChange() { + if (this.form.controls.operator.value === 'nl' || this.form.controls.operator.value === 'nnl') { + this.form.controls.value.disable(); + } else { + this.form.controls.value.enable(); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/date.component.html b/client/src/app/instance/search/components/criteria/search-type/date.component.html index 83e86d7cc77d815ce171dc0a7dd8d8197b13cd30..557801aa93fa1f738fc5f3bc5c40200cd9a17602 100644 --- a/client/src/app/instance/search/components/criteria/search-type/date.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/date.component.html @@ -1,7 +1,7 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-sm-0"> - <select class="custom-select" formControlName="operator"> + <select class="custom-select" formControlName="operator" (change)="operatorOnChange()"> <option *ngFor="let o of operators" [ngValue]="o.value">{{ o.label }}</option> </select> </div> diff --git a/client/src/app/instance/search/components/criteria/search-type/date.component.ts b/client/src/app/instance/search/components/criteria/search-type/date.component.ts index 2688daddd0292a3b7f12a0f62be6e22599fe6138..9a5ea5681bc81efd3466bfbec95989ada1ad5a1f 100644 --- a/client/src/app/instance/search/components/criteria/search-type/date.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/date.component.ts @@ -1,8 +1,18 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { AbstractSearchTypeComponent } from './abstract-search-type.component'; import { Criterion, FieldCriterion } from 'src/app/instance/store/models'; +import { searchTypeOperators } from 'src/app/shared/utils'; @Component({ selector: 'app-date', @@ -24,7 +34,9 @@ export class DateComponent extends AbstractSearchTypeComponent { } else { this.form.controls.operator.setValue(this.attribute.operator); if (!this.attribute.dynamic_operator) { - this.form.controls.operator.disable(); + this.operators = searchTypeOperators.filter( + operator => [this.attribute.operator, 'nl', 'nnl'].includes(operator.value) + ); } } } @@ -84,4 +96,12 @@ export class DateComponent extends AbstractSearchTypeComponent { const day = ('0' + (date.getDate())).slice(-2); return `${date.getFullYear()}-${month}-${day}`; } + + operatorOnChange() { + if (this.form.controls.operator.value === 'nl' || this.form.controls.operator.value === 'nnl') { + this.form.controls.date.disable(); + } else { + this.form.controls.date.enable(); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/datetime.component.html b/client/src/app/instance/search/components/criteria/search-type/datetime.component.html index d03b4e08c69e264e2ce284460954034c420147d8..45437cf8579bc7cf5e589cac55e8001967b23f88 100644 --- a/client/src/app/instance/search/components/criteria/search-type/datetime.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/datetime.component.html @@ -1,7 +1,7 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-lg-0"> - <select class="custom-select" formControlName="operator"> + <select class="custom-select" formControlName="operator" (change)="operatorOnChange()"> <option *ngFor="let o of operators" [ngValue]="o.value">{{ o.label }}</option> </select> </div> diff --git a/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts b/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts index 3348e22d5d40b084a25f4ccd6da1b758914ee277..653f8363e3f7258b6a3df928991452d88a601341 100644 --- a/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/datetime.component.ts @@ -1,8 +1,18 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { AbstractSearchTypeComponent } from './abstract-search-type.component'; import { Criterion, FieldCriterion } from 'src/app/instance/store/models'; +import { searchTypeOperators } from 'src/app/shared/utils'; @Component({ selector: 'app-datetime', @@ -36,11 +46,13 @@ export class DateTimeComponent extends AbstractSearchTypeComponent { } else { this.form.controls.operator.setValue(this.attribute.operator); if (!this.attribute.dynamic_operator) { - this.form.controls.operator.disable(); + this.operators = searchTypeOperators.filter( + operator => [this.attribute.operator, 'nl', 'nnl'].includes(operator.value) + ); } } } - + /** * Return new criterion * @@ -101,4 +113,16 @@ export class DateTimeComponent extends AbstractSearchTypeComponent { const day = ('0' + (date.getDate())).slice(-2); return `${date.getFullYear()}-${month}-${day}`; } + + operatorOnChange() { + if (this.form.controls.operator.value === 'nl' || this.form.controls.operator.value === 'nnl') { + this.form.controls.date.disable(); + this.form.controls.hh.disable(); + this.form.controls.mm.disable(); + } else { + this.form.controls.date.enable(); + this.form.controls.hh.enable(); + this.form.controls.mm.enable(); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/field.component.html b/client/src/app/instance/search/components/criteria/search-type/field.component.html index b3d12bd76d81ab032a5eb8a4580ece415db99bd4..9d878f528b1955392136a2082d8a0dbfd4fc9d8a 100644 --- a/client/src/app/instance/search/components/criteria/search-type/field.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/field.component.html @@ -1,7 +1,7 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-sm-0"> - <select class="custom-select" formControlName="operator"> + <select class="custom-select" formControlName="operator" (change)="operatorOnChange()"> <option *ngFor="let o of operators" [ngValue]="o.value">{{ o.label }}</option> </select> </div> diff --git a/client/src/app/instance/search/components/criteria/search-type/field.component.ts b/client/src/app/instance/search/components/criteria/search-type/field.component.ts index 141a4e06635a435f79ff258e923d96a3e74fcfb1..4a83e051bb1aebce5bcf99c37784d95eb07fc60e 100644 --- a/client/src/app/instance/search/components/criteria/search-type/field.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/field.component.ts @@ -1,8 +1,18 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { AbstractSearchTypeComponent } from './abstract-search-type.component'; import { Criterion, FieldCriterion } from 'src/app/instance/store/models'; +import { searchTypeOperators } from 'src/app/shared/utils'; @Component({ selector: 'app-field', @@ -22,7 +32,9 @@ export class FieldComponent extends AbstractSearchTypeComponent { if (!criterion) { this.form.controls.operator.setValue(this.attribute.operator); if (!this.attribute.dynamic_operator) { - this.form.controls.operator.disable(); + this.operators = searchTypeOperators.filter( + operator => [this.attribute.operator, 'nl', 'nnl'].includes(operator.value) + ); } } } @@ -51,6 +63,14 @@ export class FieldComponent extends AbstractSearchTypeComponent { } } + operatorOnChange() { + if (this.form.controls.operator.value === 'nl' || this.form.controls.operator.value === 'nnl') { + this.form.controls.value.disable(); + } else { + this.form.controls.value.enable(); + } + } + /** * Return placeholder. * diff --git a/client/src/app/instance/search/components/criteria/search-type/json.component.html b/client/src/app/instance/search/components/criteria/search-type/json.component.html index 0c9b7b95527467d394696d04edbf653593b7a722..81477fd60035ca0a052cbef6e8c1446427f40a46 100644 --- a/client/src/app/instance/search/components/criteria/search-type/json.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/json.component.html @@ -1,7 +1,9 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-lg-0"> - <div class="operator_readonly">json</div> + <select class="custom-select" formControlName="label" (change)="labelOnChange()"> + <option *ngFor="let l of labels" [ngValue]="l.value">{{ l.label }}</option> + </select> </div> <div class="w-100 d-block d-sm-none"></div> <div class="col pl-sm-1"> diff --git a/client/src/app/instance/search/components/criteria/search-type/json.component.ts b/client/src/app/instance/search/components/criteria/search-type/json.component.ts index 5e0cdc5b49e0644d33ab34c773d1e752dc4af651..1399230f55a9e7be55ae4c6646103dd52c04641b 100644 --- a/client/src/app/instance/search/components/criteria/search-type/json.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/json.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; @@ -9,15 +18,29 @@ import { Criterion, JsonCriterion } from 'src/app/instance/store/models'; templateUrl: 'json.component.html' }) export class JsonComponent extends AbstractSearchTypeComponent { + labels = [ + { value: 'js', label: 'json' }, + { value: 'nl', label: 'null' }, + { value: 'nnl', label: 'not null' } + ]; + constructor() { super(); this.form = new FormGroup({ + label: new FormControl(''), path: new FormControl('', [Validators.required]), operator: new FormControl('', [Validators.required]), value: new FormControl('', [Validators.required]) }); } - + + setCriterion(criterion: Criterion) { + super.setCriterion(criterion); + if (!criterion) { + this.form.controls.label.setValue('js'); + } + } + /** * Return new criterion * @@ -30,4 +53,17 @@ export class JsonComponent extends AbstractSearchTypeComponent { ...this.form.value } as JsonCriterion; } + + labelOnChange() { + if (this.form.controls.label.value === 'nl' || this.form.controls.label.value === 'nnl') { + this.nullOrNotNull = this.form.controls.label.value; + this.form.controls.operator.disable(); + this.form.controls.path.disable(); + this.form.controls.value.disable(); + } else { + this.form.controls.operator.enable(); + this.form.controls.path.enable(); + this.form.controls.value.enable(); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/list.component.html b/client/src/app/instance/search/components/criteria/search-type/list.component.html index 49e1f5f3b6c1edbb7bbad6d3ca5dfb9b418300cd..ec7caa9db52a737b0e319014ca81a08b0ba82bdc 100644 --- a/client/src/app/instance/search/components/criteria/search-type/list.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/list.component.html @@ -1,11 +1,14 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-lg-0"> - <div class="operator_readonly">=</div> + <select class="custom-select" formControlName="label" (change)="labelOnChange()"> + <option *ngFor="let l of labels" [ngValue]="l.value">{{ l.label }}</option> + </select> </div> <div class="w-100 d-block d-sm-none"></div> <div class="col pl-sm-1"> - <textarea class="form-control" rows="3" [placeholder]="getPlaceholder()" formControlName="list" autocomplete="off"></textarea> + <textarea class="form-control" rows="3" [placeholder]="getPlaceholder()" formControlName="list" + autocomplete="off"></textarea> </div> </div> -</form> +</form> \ No newline at end of file diff --git a/client/src/app/instance/search/components/criteria/search-type/list.component.ts b/client/src/app/instance/search/components/criteria/search-type/list.component.ts index d065ccdc32db9a0cc686e33644f6c916275ede09..4383525e3153cc0f1b8132c701f19ee28d526f82 100644 --- a/client/src/app/instance/search/components/criteria/search-type/list.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/list.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; @@ -9,9 +18,16 @@ import { Criterion, ListCriterion } from 'src/app/instance/store/models'; templateUrl: 'list.component.html' }) export class ListComponent extends AbstractSearchTypeComponent { + labels = [ + { value: 'in', label: 'in' }, + { value: 'nl', label: 'null' }, + { value: 'nnl', label: 'not null' } + ]; + constructor() { super(); this.form = new FormGroup({ + label: new FormControl(''), list: new FormControl('', [Validators.required]) }); } @@ -21,9 +37,11 @@ export class ListComponent extends AbstractSearchTypeComponent { if (criterion) { this.form.controls.list.setValue((criterion as ListCriterion).values.join('\n')); this.form.disable(); + } else { + this.form.controls.label.setValue('in'); } } - + /** * Return new criterion * @@ -49,4 +67,13 @@ export class ListComponent extends AbstractSearchTypeComponent { return this.attribute.placeholder_min; } } + + labelOnChange() { + if (this.form.controls.label.value === 'nl' || this.form.controls.label.value === 'nnl') { + this.nullOrNotNull = this.form.controls.label.value; + this.form.controls.list.disable(); + } else { + this.form.controls.list.enable(); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/radio.component.html b/client/src/app/instance/search/components/criteria/search-type/radio.component.html index 6267fffa7ac10501629397068127d0c8e9bd26d8..3ace3b9bba7727c0f7f2eb802cff90a63b374dfc 100644 --- a/client/src/app/instance/search/components/criteria/search-type/radio.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/radio.component.html @@ -1,7 +1,7 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-sm-0"> - <select class="custom-select" formControlName="operator"> + <select class="custom-select" formControlName="operator" (change)="operatorOnChange()"> <option *ngFor="let o of operators" [ngValue]="o.value">{{ o.label }}</option> </select> </div> diff --git a/client/src/app/instance/search/components/criteria/search-type/radio.component.ts b/client/src/app/instance/search/components/criteria/search-type/radio.component.ts index 8aa7fa5cffc5ca5182c4137f3496ee1c2be82eab..b372f83f4da954adf2370e3cb2c3ecbe503d89b5 100644 --- a/client/src/app/instance/search/components/criteria/search-type/radio.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/radio.component.ts @@ -1,8 +1,18 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { AbstractSearchTypeComponent } from './abstract-search-type.component'; import { Criterion, FieldCriterion } from 'src/app/instance/store/models'; +import { searchTypeOperators } from 'src/app/shared/utils'; @Component({ selector: 'app-radio', @@ -24,7 +34,9 @@ export class RadioComponent extends AbstractSearchTypeComponent { } else { this.form.controls.operator.setValue(this.attribute.operator); if (!this.attribute.dynamic_operator) { - this.form.controls.operator.disable(); + this.operators = searchTypeOperators.filter( + operator => [this.attribute.operator, 'nl', 'nnl'].includes(operator.value) + ); } } } @@ -59,4 +71,12 @@ export class RadioComponent extends AbstractSearchTypeComponent { this.form.controls.operator.disable(); } } + + operatorOnChange() { + if (this.form.controls.operator.value === 'nl' || this.form.controls.operator.value === 'nnl') { + this.form.controls.radio.disable(); + } else { + this.form.controls.radio.enable(); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/search-type-loader.directive.ts b/client/src/app/instance/search/components/criteria/search-type/search-type-loader.directive.ts index 74d000d5b23e6d838401e8873b41cc2b13183372..6ea1df79bfb08dbdd86e41748919a5d4a0d4a727 100644 --- a/client/src/app/instance/search/components/criteria/search-type/search-type-loader.directive.ts +++ b/client/src/app/instance/search/components/criteria/search-type/search-type-loader.directive.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Directive, ViewContainerRef } from '@angular/core'; @Directive({ diff --git a/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.html b/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.html index da9f153148f3f9d4f1035674562c6377d6ca2622..3ee473e18f6fa6c6fb8e8ae4575e2db00daa7efd 100644 --- a/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.html @@ -1,7 +1,9 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-lg-0"> - <div class="operator_readonly">in</div> + <select class="custom-select" formControlName="label" (change)="labelOnChange()"> + <option *ngFor="let l of labels" [ngValue]="l.value">{{ l.label }}</option> + </select> </div> <div class="w-100 d-block d-sm-none"></div> <div class="col pl-sm-1"> diff --git a/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.ts b/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.ts index 17c7b8d7e330453490055ad4197b1d49af2b297a..e514d0866d819176ccddf2177b8f31a93dfb2e93 100644 --- a/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; @@ -9,9 +18,16 @@ import { Criterion, SelectMultipleCriterion } from 'src/app/instance/store/model templateUrl: 'select-multiple.component.html' }) export class SelectMultipleComponent extends AbstractSearchTypeComponent { + labels = [ + { value: 'in', label: 'in' }, + { value: 'nl', label: 'null' }, + { value: 'nnl', label: 'not null' } + ]; + constructor() { super(); this.form = new FormGroup({ + label: new FormControl(''), select: new FormControl('', [Validators.required]) }); } @@ -20,12 +36,13 @@ export class SelectMultipleComponent extends AbstractSearchTypeComponent { super.setCriterion(criterion); if (criterion) { const multipleCriterion = criterion as SelectMultipleCriterion; - const values = multipleCriterion.options.map(option => option.value); this.form.controls.select.setValue(values); + } else { + this.form.controls.label.setValue('in'); } } - + /** * Return new criterion * @@ -41,4 +58,13 @@ export class SelectMultipleComponent extends AbstractSearchTypeComponent { options } as SelectMultipleCriterion; } + + labelOnChange() { + if (this.form.controls.label.value === 'nl' || this.form.controls.label.value === 'nnl') { + this.nullOrNotNull = this.form.controls.label.value; + this.form.controls.select.disable(); + } else { + this.form.controls.select.enable(); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/select.component.html b/client/src/app/instance/search/components/criteria/search-type/select.component.html index e7b758e8c889aafd4e47aed7a12f99c9cae795d2..e1d72d96746d5707a90f64382311e3787096d2f2 100644 --- a/client/src/app/instance/search/components/criteria/search-type/select.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/select.component.html @@ -1,7 +1,7 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-sm-0"> - <select class="custom-select" formControlName="operator"> + <select class="custom-select" formControlName="operator" (change)="operatorOnChange()"> <option *ngFor="let o of operators" [ngValue]="o.value">{{ o.label }}</option> </select> </div> diff --git a/client/src/app/instance/search/components/criteria/search-type/select.component.ts b/client/src/app/instance/search/components/criteria/search-type/select.component.ts index 8ef10a5194e0644c7618815ce7612722fadab045..28b826350c29372bab5382873104ce2577c2d380 100644 --- a/client/src/app/instance/search/components/criteria/search-type/select.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/select.component.ts @@ -1,8 +1,18 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { AbstractSearchTypeComponent } from './abstract-search-type.component'; import { Criterion, FieldCriterion } from 'src/app/instance/store/models'; +import { searchTypeOperators } from 'src/app/shared/utils'; @Component({ selector: 'app-select', @@ -16,15 +26,15 @@ export class SelectComponent extends AbstractSearchTypeComponent { select: new FormControl('', [Validators.required]) }); } - + setCriterion(criterion: Criterion) { super.setCriterion(criterion); - if (criterion) { - this.form.controls.select.setValue((criterion as FieldCriterion).value); - } else { + if (!criterion) { this.form.controls.operator.setValue(this.attribute.operator); if (!this.attribute.dynamic_operator) { - this.form.controls.operator.disable(); + this.operators = searchTypeOperators.filter( + operator => [this.attribute.operator, 'nl', 'nnl'].includes(operator.value) + ); } } } @@ -58,4 +68,12 @@ export class SelectComponent extends AbstractSearchTypeComponent { this.form.controls.operator.disable(); } } + + operatorOnChange() { + if (this.form.controls.operator.value === 'nl' || this.form.controls.operator.value === 'nnl') { + this.form.controls.select.disable(); + } else { + this.form.controls.select.enable(); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/svom-json-kw.component.html b/client/src/app/instance/search/components/criteria/search-type/svom-json-kw.component.html index 07e277f16c5afd108d8a695ab2bfaa8a694c14a9..1f9e9be41381561eeebe46cc747f79c9a5d016c7 100644 --- a/client/src/app/instance/search/components/criteria/search-type/svom-json-kw.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/svom-json-kw.component.html @@ -1,7 +1,9 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-lg-0"> - <div class="operator_readonly">json</div> + <select class="custom-select" formControlName="label" (change)="labelOnChange()"> + <option *ngFor="let l of labels" [ngValue]="l.value">{{ l.label }}</option> + </select> </div> <div class="w-100 d-block d-sm-none"></div> <div class="col pl-sm-1"> diff --git a/client/src/app/instance/search/components/criteria/search-type/svom-json-kw.component.ts b/client/src/app/instance/search/components/criteria/search-type/svom-json-kw.component.ts index a0ec4f412754fe5deef38724b5087c0ef28bd4c0..399e1ef28792dee37467b247f434c18b51b12fef 100644 --- a/client/src/app/instance/search/components/criteria/search-type/svom-json-kw.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/svom-json-kw.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, ChangeDetectorRef } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { HttpClient } from '@angular/common/http'; @@ -13,16 +22,29 @@ import { Criterion, FieldCriterion, JsonCriterion, SvomKeyword } from 'src/app/i templateUrl: 'svom-json-kw.component.html' }) export class SvomJsonKwComponent extends AbstractSearchTypeComponent { + labels = [ + { value: 'js', label: 'json' }, + { value: 'nl', label: 'null' }, + { value: 'nnl', label: 'not null' } + ]; svomKeywords: SvomKeyword[] = []; constructor(private changeDetectorRef: ChangeDetectorRef, private http: HttpClient, private config: AppConfigService) { super(); this.form = new FormGroup({ + label: new FormControl(''), path: new FormControl('', [Validators.required]), operator: new FormControl('', [Validators.required]), value: new FormControl('', [Validators.required]) }); } + + setCriterion(criterion: Criterion) { + super.setCriterion(criterion); + if (!criterion) { + this.form.controls.label.setValue('js'); + } + } setCriteriaList(criteriaList: Criterion[]): void { super.setCriteriaList(criteriaList); @@ -63,4 +85,17 @@ export class SvomJsonKwComponent extends AbstractSearchTypeComponent { getKeywordValue(svomKeyword: SvomKeyword): string { return `${svomKeyword.extension},${svomKeyword.name}` } + + labelOnChange() { + if (this.form.controls.label.value === 'nl' || this.form.controls.label.value === 'nnl') { + this.nullOrNotNull = this.form.controls.label.value; + this.form.controls.operator.disable(); + this.form.controls.path.disable(); + this.form.controls.value.disable(); + } else { + this.form.controls.operator.enable(); + this.form.controls.path.enable(); + this.form.controls.value.enable(); + } + } } diff --git a/client/src/app/instance/search/components/criteria/search-type/time.component.html b/client/src/app/instance/search/components/criteria/search-type/time.component.html index f56adb811b4c5db9d5ce1f23fde0b62053f8f73a..4be22d32af409726e327b53243821edf0267f399 100644 --- a/client/src/app/instance/search/components/criteria/search-type/time.component.html +++ b/client/src/app/instance/search/components/criteria/search-type/time.component.html @@ -1,7 +1,7 @@ <form [formGroup]="form" novalidate> <div class="row form-group"> <div class="col-md-3 col-sm-auto pr-sm-1 mb-1 mb-lg-0"> - <select class="custom-select" formControlName="operator"> + <select class="custom-select" formControlName="operator" (change)="operatorOnChange()"> <option *ngFor="let o of operators" [ngValue]="o.value">{{ o.label }}</option> </select> </div> diff --git a/client/src/app/instance/search/components/criteria/search-type/time.component.ts b/client/src/app/instance/search/components/criteria/search-type/time.component.ts index 12d3df31fcc2a061531801f7f28c8b161a43ea21..eddc3134205470b81e86cdaa5bcc7f06b7044209 100644 --- a/client/src/app/instance/search/components/criteria/search-type/time.component.ts +++ b/client/src/app/instance/search/components/criteria/search-type/time.component.ts @@ -1,8 +1,18 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { AbstractSearchTypeComponent } from './abstract-search-type.component'; import { Criterion, FieldCriterion } from 'src/app/instance/store/models'; +import { searchTypeOperators } from 'src/app/shared/utils'; @Component({ selector: 'app-time', @@ -33,11 +43,13 @@ export class TimeComponent extends AbstractSearchTypeComponent { } else { this.form.controls.operator.setValue(this.attribute.operator); if (!this.attribute.dynamic_operator) { - this.form.controls.operator.disable(); + this.operators = searchTypeOperators.filter( + operator => [this.attribute.operator, 'nl', 'nnl'].includes(operator.value) + ); } } } - + /** * Return new criterion * @@ -83,4 +95,14 @@ export class TimeComponent extends AbstractSearchTypeComponent { } return array; } + + operatorOnChange() { + if (this.form.controls.operator.value === 'nl' || this.form.controls.operator.value === 'nnl') { + this.form.controls.hh.disable(); + this.form.controls.mm.disable(); + } else { + this.form.controls.hh.enable(); + this.form.controls.mm.enable(); + } + } } diff --git a/client/src/app/instance/search/containers/criteria.component.html b/client/src/app/instance/search/containers/criteria.component.html index 794cadbcf9f73c66ce62cb55fd214ad3ea8b5690..f7c4ac0a287df5198ec841c43483bbdb0a00a3fd 100644 --- a/client/src/app/instance/search/containers/criteria.component.html +++ b/client/src/app/instance/search/containers/criteria.component.html @@ -3,7 +3,8 @@ || (attributeListIsLoading | async) || (coneSearchConfigIsLoading | async)"> </app-spinner> - +<app-criteria-list [attributeList]="attributeList |async" [criteriaList]="criteriaList | async" *ngIf="(criteriaList | async).length"> +</app-criteria-list> <div *ngIf="(datasetListIsLoaded | async) && (criteriaFamilyListIsLoaded | async) && (attributeListIsLoaded | async) diff --git a/client/src/app/shared/utils.ts b/client/src/app/shared/utils.ts index 528e9afa6396312b35b6749f2d8bf6c602b94b99..262594e1d8411494fe97ae3d7b726af9f10e3d55 100644 --- a/client/src/app/shared/utils.ts +++ b/client/src/app/shared/utils.ts @@ -49,5 +49,7 @@ export const searchTypeOperators: SearchTypeOperator[] = [ { value: 'lk', label: 'like' }, { value: 'nlk', label: 'not like' }, { value: 'in', label: 'in' }, - { value: 'nin', label: 'not in' } + { value: 'nin', label: 'not in' }, + { value: 'nl', label: 'null' }, + { value: 'nnl', label: 'not null' }, ];