Skip to content
Snippets Groups Projects
Commit a9910181 authored by François Agneray's avatar François Agneray
Browse files

Add instance shared module

parent a97b3b64
No related branches found
No related tags found
No related merge requests found
Showing
with 1229 additions and 0 deletions
<div class="row px-3">
<label>DEC</label>
<div class="input-group">
<input type="text" class="form-control" [formControl]="decDegree" (input)="decChange()" autocomplete="off">
<div class="input-group-append">
<span class="input-group-text">°</span>
</div>
</div>
</div>
<div class="row mt-2 px-3">
<div class="col px-0 pr-xl-1">
<div class="input-group">
<input type="text"
class="form-control"
[formControl]="decH"
(input)="decChange()"
(focusin)="changeFocus('dech', true)"
(focusout)="changeFocus('dech', false)"
(change)="setToDefaultValue()"
autocomplete="off">
<div class="input-group-append">
<span class="input-group-text">°</span>
</div>
</div>
</div>
<div class="w-100 d-block d-xl-none"></div>
<div class="col mt-1 mt-xl-auto px-0 pr-xl-1">
<div class="input-group">
<input type="text"
class="form-control"
[formControl]="decM"
(input)="decChange()"
(focusin)="changeFocus('decm', true)"
(focusout)="changeFocus('decm', false)"
(change)="setToDefaultValue()"
autocomplete="off">
<div class="input-group-append">
<span class="input-group-text">'</span>
</div>
</div>
</div>
<div class="w-100 d-block d-xl-none"></div>
<div class="col mt-1 mt-xl-auto px-0">
<div class="input-group">
<input type="text"
class="form-control"
[formControl]="decS"
(input)="decChange()"
(focusin)="changeFocus('decs', true)"
(focusout)="changeFocus('decs', false)"
(change)="setToDefaultValue()"
autocomplete="off">
<div class="input-group-append">
<span class="input-group-text">''</span>
</div>
</div>
</div>
</div>
<div *ngIf="decDegree.invalid" class="row px-3 text-danger">
<div *ngIf="decDegree.errors.nan">
{{ decDegree.errors.nan.value }}
</div>
<div *ngIf="decDegree.errors.range" [hidden]="decDegree.errors.nan">
{{ decDegree.errors.range.value }}
</div>
</div>
<div *ngIf="decH.invalid" class="row px-3 text-danger">
<div *ngIf="decH.errors.nan">
{{ decH.errors.nan.value }}
</div>
<div *ngIf="decH.errors.range" [hidden]="decH.errors.nan">
{{ decH.errors.range.value }}
</div>
</div>
<div *ngIf="decM.invalid" class="row px-3 text-danger">
<div *ngIf="decM.errors.nan">
{{ decM.errors.nan.value }}
</div>
<div *ngIf="decM.errors.range" [hidden]="decM.errors.nan">
{{ decM.errors.range.value }}
</div>
</div>
<div *ngIf="decS.invalid" class="row px-3 text-danger">
<div *ngIf="decS.errors.nan">
{{ decS.errors.nan.value }}
</div>
<div *ngIf="decS.errors.range" [hidden]="decS.errors.nan">
{{ decS.errors.range.value }}
</div>
</div>
/**
* 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 { FormControl, Validators } from '@angular/forms';
import { nanValidator, rangeValidator } from '../../validators';
import { ConeSearch, Resolver } from 'src/app/instance/store/models';
@Component({
selector: 'app-dec',
templateUrl: 'dec.component.html',
styleUrls: ['input-group.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
/**
* @class
* @classdesc DEC component.
*/
export class DecComponent {
/**
* Disables DEC fields.
*
* @param {boolean} disabled - If the field has to be disabled.
*/
@Input()
set disabled(disabled: boolean) {
this.isDisabled = disabled;
this.initFields();
}
/**
* Sets RA, DEC and radius from cone search.
*
* @param {ConeSearch} coneSearch - The cone search.
*/
@Input()
set coneSearch(coneSearch: ConeSearch) {
this.ra = coneSearch.ra;
this.radius = coneSearch.radius;
if (coneSearch.dec) {
this.decDegree.setValue(coneSearch.dec);
if(this.decDegree.valid && !this.decHFocused && !this.decMFocused && !this.decSFocused) {
this.decDegree2HMS(coneSearch.dec);
}
} else {
this.decDegree.reset();
this.decH.reset();
this.decM.reset();
this.decS.reset();
}
this.initFields();
}
/**
* Sets RA from resolver.
*
* @param {Resolver} resolver - The resolver.
*/
@Input()
set resolver(resolver: Resolver) {
this.resolvedDec = null;
if (resolver) {
this.resolvedDec = resolver.dec;
this.decDegree.setValue(resolver.dec);
this.decDegree2HMS(resolver.dec);
}
}
/**
* Sets isDegree.
*
* @param {string} unit - The unit.
*/
@Input()
set unit(unit: string) {
unit === 'degree' ? this.isDegree = true : this.isDegree = false;
this.initFields();
}
@Output() updateConeSearch: EventEmitter<ConeSearch> = new EventEmitter();
@Output() deleteResolver: EventEmitter<null> = new EventEmitter();
ra: number;
radius: number;
isDisabled = false;
isDegree = true;
resolvedDec: number;
decHFocused: boolean = false;
decMFocused: boolean = false;
decSFocused: boolean = false;
decDegree = new FormControl('', [Validators.required, nanValidator, rangeValidator(-90, 90, 'DEC')]);
decH = new FormControl('', [nanValidator, rangeValidator(-90, 90, 'Degree')]);
decM = new FormControl('', [nanValidator, rangeValidator(0, 60, 'Minutes')]);
decS = new FormControl('', [nanValidator, rangeValidator(0, 60, 'Seconds')]);
/**
* Sets DEC fields.
*/
initFields(): void {
if (this.isDisabled) {
this.decDegree.disable();
this.decH.disable();
this.decM.disable();
this.decS.disable();
} else if (this.isDegree) {
this.decDegree.enable();
this.decH.disable();
this.decM.disable();
this.decS.disable();
} else {
this.decDegree.disable();
this.decH.enable();
this.decM.enable();
this.decS.enable();
}
}
/**
* Converts DEC hour minute second from degree and sets DEC HMS fields.
*
* @param {number} value - The degree value.
*/
decDegree2HMS(value: number): void {
const hh = Math.trunc(value);
let tmp = (Math.abs(value - hh)) * 60;
const mm = Math.trunc(tmp);
tmp = (tmp - mm) * 60;
const ss = tmp.toFixed(2);
this.decH.setValue(hh);
this.decM.setValue(mm);
this.decS.setValue(ss);
}
/**
* Sets DEC degree from hour minute second and sets DEC degree field.
*/
decHMS2Degree(): void {
const hh = +this.decH.value;
const mm = +this.decM.value;
const ss = +this.decS.value;
const tmp = ((ss / 60) + mm) / 60;
let deg = tmp + Math.abs(hh);
if (hh < 0) {
deg = -deg;
}
this.decDegree.setValue(+deg.toFixed(8));
}
/**
* Changes fields focus.
*
* @param {string} field - The field.
* @param {boolean} isFocused - Is the field is focused.
*/
changeFocus(field: string, isFocused: boolean) {
switch (field) {
case 'dech':
this.decHFocused = isFocused;
break;
case 'decm':
this.decMFocused = isFocused;
break
case 'decs':
this.decSFocused = isFocused;
break;
}
}
/**
* Manages DEC value change.
*/
decChange(): void {
if (this.isDegree) {
if (this.decDegree.valid) {
this.decDegree2HMS(this.decDegree.value);
} else {
this.decH.reset();
this.decM.reset();
this.decS.reset();
}
this.updateConeSearch.emit({ ra: this.ra, dec: this.decDegree.value, radius: this.radius } as ConeSearch);
} else {
if (this.decH.valid && this.decM.valid && this.decS.valid) {
this.setToDefaultValue();
this.decHMS2Degree();
this.updateConeSearch.emit({ ra: this.ra, dec: this.decDegree.value, radius: this.radius } as ConeSearch);
} else {
this.decDegree.reset();
}
}
this.resetResolver();
}
/**
* Sets DEC hour minute second fields to default value if not valid.
*/
setToDefaultValue(): void {
if (this.decH.value === '' || this.decH.value === null) {
this.decH.setValue(0);
}
if (this.decM.value === '' || this.decM.value === null) {
this.decM.setValue(0);
}
if (this.decS.value === '' || this.decS.value === null) {
this.decS.setValue(0);
}
}
/**
* Emits reset resolver event.
*/
resetResolver(): void {
if (this.resolvedDec && this.resolvedDec !== this.decDegree.value) {
this.deleteResolver.emit();
}
}
}
import { ConeSearchComponent } from './cone-search.component';
import { ResolverComponent } from './resolver.component';
import { RaComponent } from './ra.component';
import { DecComponent } from './dec.component';
import { RadiusComponent } from './radius.component';
export const coneSearchComponents = [
ConeSearchComponent,
ResolverComponent,
RaComponent,
DecComponent,
RadiusComponent
];
/**
* 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.
*/
.input-group-text {
width: 36px;
}
<div class="row px-3">
<label>RA</label>
<div class="input-group">
<input type="text" class="form-control" [formControl]="raDegree" (input)="raChange()" autocomplete="off">
<div class="input-group-append">
<span class="input-group-text">°</span>
</div>
</div>
</div>
<div class="row mt-2 px-3">
<div class="col px-0 pr-xl-1">
<div class="input-group">
<input type="text"
class="form-control"
[formControl]="raH"
(input)="raChange()"
(focusin)="changeFocus('rah', true)"
(focusout)="changeFocus('rah', false)"
(change)="setToDefaultValue()"
autocomplete="off">
<div class="input-group-append">
<span class="input-group-text">H</span>
</div>
</div>
</div>
<div class="w-100 d-block d-xl-none"></div>
<div class="col mt-1 mt-xl-auto px-0 pr-xl-1">
<div class="input-group">
<input type="text"
class="form-control"
[formControl]="raM"
(input)="raChange()"
(focusin)="changeFocus('ram', true)"
(focusout)="changeFocus('ram', false)"
(change)="setToDefaultValue()"
autocomplete="off">
<div class="input-group-append">
<span class="input-group-text">'</span>
</div>
</div>
</div>
<div class="w-100 d-block d-xl-none"></div>
<div class="col mt-1 mt-xl-auto px-0">
<div class="input-group">
<input type="text"
class="form-control"
[formControl]="raS"
(input)="raChange()"
(focusin)="changeFocus('ras', true)"
(focusout)="changeFocus('ras', false)"
(change)="setToDefaultValue()"
autocomplete="off">
<div class="input-group-append">
<span class="input-group-text">''</span>
</div>
</div>
</div>
</div>
<div *ngIf="raDegree.invalid" class="row px-3 text-danger">
<div *ngIf="raDegree.errors.nan">
{{ raDegree.errors.nan.value }}
</div>
<div *ngIf="raDegree.errors.range" [hidden]="raDegree.errors.nan">
{{ raDegree.errors.range.value }}
</div>
</div>
<div *ngIf="raH.invalid" class="row px-3 text-danger">
<div *ngIf="raH.errors.nan">
{{ raH.errors.nan.value }}
</div>
<div *ngIf="raH.errors.range" [hidden]="raH.errors.nan">
{{ raH.errors.range.value }}
</div>
</div>
<div *ngIf="raM.invalid" class="row px-3 text-danger">
<div *ngIf="raM.errors.nan">
{{ raM.errors.nan.value }}
</div>
<div *ngIf="raM.errors.range" [hidden]="raM.errors.nan">
{{ raM.errors.range.value }}
</div>
</div>
<div *ngIf="raS.invalid" class="row px-3 text-danger">
<div *ngIf="raS.errors.nan">
{{ raS.errors.nan.value }}
</div>
<div *ngIf="raS.errors.range" [hidden]="raS.errors.nan">
{{ raS.errors.range.value }}
</div>
</div>
/**
* 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 { FormControl, Validators } from '@angular/forms';
import { nanValidator, rangeValidator } from '../../validators';
import { ConeSearch, Resolver } from 'src/app/instance/store/models';
@Component({
selector: 'app-ra',
templateUrl: 'ra.component.html',
styleUrls: ['input-group.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
/**
* @class
* @classdesc RA component.
*/
export class RaComponent {
/**
* Disables RA fields.
*
* @param {boolean} disabled - If the field has to be disabled.
*/
@Input()
set disabled(disabled: boolean) {
this.isDisabled = disabled;
this.initFields();
}
/**
* Sets RA, DEC and radius from cone search.
*
* @param {ConeSearch} coneSearch - The cone search.
*/
@Input()
set coneSearch(coneSearch: ConeSearch) {
this.dec = coneSearch.dec;
this.radius = coneSearch.radius;
if (coneSearch.ra) {
this.raDegree.setValue(coneSearch.ra);
if (this.raDegree.valid && !this.raHFocused && !this.raMFocused && !this.raSFocused) {
this.raDegree2HMS(coneSearch.ra);
}
} else {
this.raDegree.reset();
this.raH.reset();
this.raM.reset();
this.raS.reset();
}
this.initFields();
}
/**
* Sets RA from resolver.
*
* @param {Resolver} resolver - The resolver.
*/
@Input()
set resolver(resolver: Resolver) {
this.resolvedRa = null;
if (resolver) {
this.resolvedRa = resolver.ra;
this.raDegree.setValue(resolver.ra);
this.raDegree2HMS(resolver.ra);
}
}
/**
* Sets isDegree.
*
* @param {string} unit - The unit.
*/
@Input()
set unit(unit: string) {
unit === 'degree' ? this.isDegree = true : this.isDegree = false;
this.initFields();
}
@Output() updateConeSearch: EventEmitter<ConeSearch> = new EventEmitter();
@Output() deleteResolver: EventEmitter<null> = new EventEmitter();
dec: number = null;
radius: number = null;
isDisabled = false;
isDegree = true;
resolvedRa: number;
raHFocused: boolean = false;
raMFocused: boolean = false;
raSFocused: boolean = false;
raDegree = new FormControl('', [Validators.required, nanValidator, rangeValidator(0, 360, 'RA')]);
raH = new FormControl('', [nanValidator, rangeValidator(0, 24, 'Hours')]);
raM = new FormControl('', [nanValidator, rangeValidator(0, 60, 'Minutes')]);
raS = new FormControl('', [nanValidator, rangeValidator(0, 60, 'Seconds')]);
/**
* Sets RA fields.
*/
initFields(): void {
if (this.isDisabled) {
this.raDegree.disable();
this.raH.disable();
this.raM.disable();
this.raS.disable();
} else if (this.isDegree) {
this.raDegree.enable();
this.raH.disable();
this.raM.disable();
this.raS.disable();
} else {
this.raDegree.disable();
this.raH.enable();
this.raM.enable();
this.raS.enable();
}
}
/**
* Converts RA hour minute second from degree and sets RA HMS fields.
*
* @param {number} value - The degree value.
*/
raDegree2HMS(value: number): void {
let tmp = value / 15;
const hh = Math.trunc(tmp);
tmp = (tmp - hh) * 60;
const mm = Math.trunc(tmp);
tmp = (tmp - mm) * 60;
const ss = +tmp.toFixed(2);
this.raH.setValue(hh);
this.raM.setValue(mm);
this.raS.setValue(ss);
}
/**
* Sets RA degree from hour minute second and sets RA degree field.
*/
raHMS2Degree(): void {
const hh = +this.raH.value;
const mm = +this.raM.value;
const ss = +this.raS.value;
const deg = +(((((ss / 60) + mm) / 60) + hh) * 15).toFixed(8);
this.raDegree.setValue(deg);
}
/**
* Changes fields focus.
*
* @param {string} field - The field.
* @param {boolean} isFocused - Is the field is focused.
*/
changeFocus(field: string, isFocused: boolean): void {
switch (field) {
case 'rah':
this.raHFocused = isFocused;
break;
case 'ram':
this.raMFocused = isFocused;
break
case 'ras':
this.raSFocused = isFocused;
break;
}
}
/**
* Manages RA value change.
*/
raChange(): void {
if (this.isDegree) {
if (this.raDegree.valid) {
this.raDegree2HMS(this.raDegree.value);
} else {
this.raH.reset();
this.raM.reset();
this.raS.reset();
}
this.updateConeSearch.emit({ ra: this.raDegree.value, dec: this.dec, radius: this.radius } as ConeSearch);
} else {
if (this.raH.valid && this.raM.valid && this.raS.valid) {
this.setToDefaultValue();
this.raHMS2Degree();
this.updateConeSearch.emit({ ra: this.raDegree.value, dec: this.dec, radius: this.radius } as ConeSearch);
} else {
this.raDegree.reset();
}
}
this.resetResolver();
}
/**
* Sets RA hour minute second fields to default value if not valid.
*/
setToDefaultValue(): void {
if (this.raH.value === '' || this.raH.value === null) {
this.raH.setValue(0);
}
if (this.raM.value === '' || this.raM.value === null) {
this.raM.setValue(0);
}
if (this.raS.value === '' || this.raS.value === null) {
this.raS.setValue(0);
}
}
/**
* Emits reset resolver event.
*/
resetResolver(): void {
if (this.resolvedRa && this.resolvedRa !== this.raDegree.value) {
this.deleteResolver.emit();
}
}
}
<div class="row">
<div class="col form-group mb-0">
<label>Radius</label>
<input #rr
type="range"
min="0"
max="150"
[formControl]="radiusRange"
(input)="radiusChange(rr.value)"
class="form-control-range mt-2"
autocomplete="off">
</div>
<div class="w-100 d-block d-lg-none"></div>
<div class="col col-lg-auto form-group mb-0">
<div class="input-group mt-4">
<input #rf id="radius-field" type="number" class="form-control" [formControl]="radiusField" (input)="radiusChange(rf.value)" autocomplete="off">
<div class="input-group-append">
<span class="input-group-text">arcsecond</span>
</div>
</div>
</div>
<div *ngIf="radiusField.invalid" class="col-12 text-danger">
<div *ngIf="radiusField.errors.range">
{{ radiusField.errors.range.value }}
</div>
</div>
</div>
/**
* 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.
*/
@media (min-width: 992px) {
#radius-field {
width: 100px;
}
}
/**
* 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 { FormControl } from '@angular/forms';
import { rangeValidator } from '../../validators';
import { ConeSearch } from 'src/app/instance/store/models';
@Component({
selector: 'app-radius',
templateUrl: 'radius.component.html',
styleUrls: ['radius.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
/**
* @class
* @classdesc Radius component.
*/
export class RadiusComponent {
/**
* Sets RA, DEC and radius from cone search.
*
* @param {ConeSearch} coneSearch - The cone search.
*/
@Input()
set coneSearch(coneSearch: ConeSearch) {
this.ra = coneSearch.ra;
this.dec = coneSearch.dec;
if (coneSearch.radius) {
this.radiusField.setValue(coneSearch.radius);
this.radiusRange.setValue(coneSearch.radius);
} else {
this.radiusRange.setValue(0);
this.radiusField.setValue(0);
}
}
/**
* Disables radius fields.
*
* @param {boolean} disabled - If the field has to be disabled.
*/
@Input()
set disabled(disabled: boolean) {
if (disabled) {
this.radiusField.disable();
this.radiusRange.disable();
} else {
this.radiusField.enable();
this.radiusRange.enable();
}
}
@Output() updateConeSearch: EventEmitter<ConeSearch> = new EventEmitter();
ra: number;
dec: number;
radiusRange = new FormControl('');
radiusField = new FormControl('', [rangeValidator(0, 150, 'Radius')]);
/**
* Sets radius value form inputs and emits cone search event.
*
* @param {string} value - The value of radius.
*
* @fires EventEmitter<ConeSearch>
*/
radiusChange(value: string): void {
this.radiusField.setValue(+value);
this.radiusRange.setValue(+value);
this.updateConeSearch.emit({ ra: this.ra, dec: this.dec, radius: +value } as ConeSearch);
}
}
<div class="row">
<div class="col pr-0">
<label for="resolver">Resolve RA and DEC with Sesame Name Resolver</label>
<input #n id="resolver" type="text" class="form-control" [formControl]="field" autocomplete="off">
</div>
<div class="col-auto pt-5 pt-lg-4">
<button *ngIf="!resolverWip" id="btn-search" class="btn btn-outline-secondary mt-2" [disabled]="field.disabled" (click)="resolveName.emit(n.value)">
<span class="fas fa-search"></span>
</button>
<button *ngIf="resolverWip" id="btn-wip" class="btn btn-outline-secondary mt-2" disabled>
<span class="fas fa-circle-notch fa-spin"></span>
<span class="sr-only">Loading...</span>
</button>
</div>
</div>
/**
* 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 { FormControl } from '@angular/forms';
import { Resolver } from 'src/app/instance/store/models';
@Component({
selector: 'app-resolver',
templateUrl: 'resolver.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
/**
* @class
* @classdesc Resolver component.
*/
export class ResolverComponent {
@Input()
set disabled(disabled: boolean) {
if (disabled) {
this.field.disable();
} else {
this.field.enable();
}
}
@Input() resolverWip: boolean;
@Input()
set resolver(resolver: Resolver) {
if (resolver) {
this.field.setValue(resolver.name);
} else {
this.field.reset();
}
}
@Output() resolveName: EventEmitter<string> = new EventEmitter();
field = new FormControl('');
}
<div *ngIf="!requiredParams()" class="text-center">
<span class="fas fa-circle-notch fa-spin fa-3x"></span>
<span class="sr-only">Loading...</span>
</div>
<div *ngIf="requiredParams()">
<div *ngIf="dataset.config.datatable.selectable_row" class="mb-2">
<button [disabled]="noSelectedData() || processWip" (click)="executeProcess.emit('csv')"
class="btn btn-sm btn-outline-primary">
To CSV
</button>
<span *ngIf="processWip" class="float-right mr-2">
<span class="fas fa-circle-notch fa-spin fa-2x"></span>
</span>
<a *ngIf="processDone" href="http://0.0.0.0:8085/{{ processId }}.csv"
class="btn btn-sm btn-outline-secondary float-right">
Download your CSV
</a>
</div>
<div class="table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th *ngIf="dataset.config.datatable.selectable_row">#</th>
<th *ngFor="let attribute of getOutputList()" scope="col" class="clickable" (click)="sort(attribute.id)">
{{ attribute.label }}
<span *ngIf="attribute.id === sortedCol" class="pl-2">
<span [ngClass]="{'active': sortedOrder === 'a', 'inactive': sortedOrder === 'd'}">
<span class="fas fa-fw fa-sort-amount-down-alt"></span>
</span>
<span [ngClass]="{'active': sortedOrder === 'd', 'inactive': sortedOrder === 'a'}">
<span class="fas fa-fw fa-sort-amount-up"></span>
</span>
</span>
<span *ngIf="attribute.id !== sortedCol" class="pl-2">
<span class="unsorted">
<span class="fas fa-fw fa-arrows-alt-v"></span>
</span>
<span class="on-hover">
<span class="fas fa-fw fa-sort-amount-down-alt"></span>
</span>
</span>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let datum of data">
<td *ngIf="dataset.config.datatable.selectable_row" class="data-selected"
(click)="toggleSelection(datum)">
<button class="btn btn-block text-left p-0 m-0">
<span *ngIf="!isSelected(datum)">
<span class="far fa-square fa-lg text-secondary"></span>
</span>
<span *ngIf="isSelected(datum)">
<span class="fas fa-check-square fa-lg theme-color"></span>
</span>
</button>
</td>
<td *ngFor="let attribute of getOutputList()" class="align-middle">
<div [ngSwitch]="attribute.renderer">
<div *ngSwitchCase="'detail'">
<app-detail
[value]="datum[attribute.label]"
[datasetName]="dataset.name"
[config]="attribute.renderer_config">
</app-detail>
</div>
<div *ngSwitchCase="'link'">
<app-link
[value]="datum[attribute.label]"
[datasetName]="dataset.name"
[config]="attribute.renderer_config">
</app-link>
</div>
<div *ngSwitchCase="'download'">
<app-download
[value]="datum[attribute.label]"
[datasetName]="dataset.name"
[config]="attribute.renderer_config">
</app-download>
</div>
<div *ngSwitchCase="'image'">
<app-image
[value]="datum[attribute.label]"
[datasetName]="dataset.name"
[config]="attribute.renderer_config">
</app-image>
</div>
<div *ngSwitchCase="'json'">
<app-json
[value]="datum[attribute.label]"
[attributeLabel]="attribute.label"
[config]="attribute.renderer_config">
</app-json>
</div>
<div *ngSwitchDefault>
{{ datum[attribute.label] }}
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="row mt-3">
<div class="col">
Showing
<select class="custom-select" (change)="changeNbItems($event.target.value)">
<option value="10" selected="true">10</option>
<option value="20">20</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
of {{ dataLength }} items
</div>
<div class="col-auto">
<pagination
[(ngModel)]="page"
[totalItems]="dataLength"
[boundaryLinks]="true"
[rotate]="true"
[maxSize]="5"
[itemsPerPage]="nbItems"
previousText="&lsaquo;" nextText="&rsaquo;" firstText="&laquo;" lastText="&raquo;"
(pageChanged)="changePage($event.page)">
</pagination>
</div>
</div>
</div>
/**
* 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.
*/
.data-selected {
cursor: pointer;
}
.data-selected button:focus {
box-shadow: none;
}
ul {
margin-bottom: 0;
}
.custom-select {
width: fit-content;
}
.clickable:hover {
cursor: pointer;
background-color: #F7F7F7;
}
.unsorted {
color: #c5c5c5;
}
.clickable:hover .unsorted, .on-hover, .inactive, .clickable:hover .active {
display: none;
}
.clickable:hover .on-hover, .clickable:hover .inactive {
display: inline;
}
/**
* 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, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Attribute, Dataset } from 'src/app/metamodel/models';
import { Pagination, PaginationOrder } from 'src/app/instance/store/models';
@Component({
selector: 'app-datatable',
templateUrl: 'datatable.component.html',
styleUrls: ['datatable.component.scss'],
})
/**
* @class
* @classdesc Datatable component.
*
* @implements OnInit
*/
export class DatatableComponent implements OnInit {
@Input() dataset: Dataset;
@Input() attributeList: Attribute[];
@Input() outputList: number[];
@Input() data: any[];
@Input() dataLength: number;
@Input() selectedData: any[] = [];
@Input() processWip: boolean = false;
@Input() processDone: boolean = false;
@Input() processId: string = null;
@Output() getData: EventEmitter<Pagination> = new EventEmitter();
@Output() addSelectedData: EventEmitter<number | string> = new EventEmitter();
@Output() deleteSelectedData: EventEmitter<number | string> = new EventEmitter();
@Output() executeProcess: EventEmitter<string> = new EventEmitter();
nbItems = 10;
page = 1;
sortedCol: number = null;
sortedOrder: PaginationOrder = PaginationOrder.a;
ngOnInit() {
this.sortedCol = this.attributeList.find(a => a.order_by).id;
}
/**
* Checks if required parameters to display datatable are passed to the component.
*
* @return boolean
*/
requiredParams(): boolean {
if (this.attributeList.length === 0 || this.outputList.length === 0 || !this.dataLength) {
return false;
}
return true;
}
/**
* Checks if there is no data selected.
*
* @return boolean
*/
noSelectedData(): boolean {
return this.selectedData.length < 1;
}
/**
* Returns output list from attribute list.
*
* @return Attribute[]
*/
getOutputList(): Attribute[] {
return this.attributeList
.filter(a => this.outputList.includes(a.id))
.sort((a, b) => a.output_display - b.output_display);
}
/**
* Emits events to select or unselect data.
*
* @param {any} datum - The data to select or unselect.
*
* @fires EventEmitter<number | string>
*/
toggleSelection(datum: any): void {
const attribute = this.attributeList.find(a => a.search_flag === 'ID');
const index = this.selectedData.indexOf(datum[attribute.label]);
if (index > -1) {
this.deleteSelectedData.emit(datum[attribute.label]);
} else {
this.addSelectedData.emit(datum[attribute.label]);
}
}
/**
* Checks if data is selected.
*
* @param {any} datum - The data.
*
* @return boolean
*/
isSelected(datum: any): boolean {
const attribute = this.attributeList.find(a => a.search_flag === 'ID');
if (this.selectedData.indexOf(datum[attribute.label]) > -1) {
return true;
}
return false;
}
/**
* Emits event to change datatable page.
*
* @param {number} nb - The page number to access.
*
* @fires EventEmitter<Pagination>
*/
changePage(nb: number): void {
this.page = nb;
const pagination: Pagination = {
dname: this.dataset.name,
page: this.page,
nbItems: this.nbItems,
sortedCol: this.sortedCol,
order: this.sortedOrder
};
this.getData.emit(pagination);
}
/**
* Emits event to change datatable displayed items.
*
* @param {number} nb - The number of items to display.
*
* @fires EventEmitter<Pagination>
*/
changeNbItems(nb: number): void {
this.nbItems = nb;
this.changePage(1);
}
/**
* Emits event to change the sorted order and the sorted column of the datatable.
*
* @param {number} id - The id of the column to sort.
*
* @fires EventEmitter<Pagination>
*/
sort(id: number): void {
if (id === this.sortedCol) {
this.sortedOrder = this.sortedOrder === PaginationOrder.a ? PaginationOrder.d : PaginationOrder.a;
} else {
this.sortedCol = id;
this.sortedOrder = PaginationOrder.a;
}
this.changePage(1);
}
}
import { DatatableComponent } from "./datatable.component";
export const datatableComponents = [
DatatableComponent
];
import { coneSearchComponents } from './cone-search';
import { datatableComponents } from './datatable';
export const sharedComponents = [
coneSearchComponents,
datatableComponents
];
import { PrettyOperatorPipe } from './pretty-operator.pipe';
export const sharedPipes = [
PrettyOperatorPipe
];
/**
* This file is part of Anis Client.
*
* @copyright Laboratoire d'Astrophysique de Marseille / CNRS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { Pipe, PipeTransform } from '@angular/core';
import { getPrettyOperator } from 'src/app/instance/store/models';
/**
* @class
* @classdesc Translate Anis string operator to a pretty form label operator.
*
* @example
* // formats eq to =
* {{ eq | prettyOperator }}
*/
@Pipe({ name: 'prettyOperator' })
export class PrettyOperatorPipe implements PipeTransform {
transform(operator: string): string {
return getPrettyOperator(operator);
}
}
/**
* 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 { sharedComponents } from './components';
import { sharedPipes } from './pipes';
@NgModule({
declarations: [
sharedComponents,
sharedPipes
],
exports: [
sharedComponents,
sharedPipes
]
})
export class SharedModule { }
export * from './range-validator.directive';
export * from './nan-validator.directive';
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment