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

Add actions for selected data

parent 6049e535
No related branches found
No related tags found
2 merge requests!29Develop,!28Selected data actions
Showing with 181 additions and 3 deletions
<div class="btn-group mb-2" dropdown [isDisabled]="selectedData.length < 1">
<button id="button-basic" dropdownToggle type="button" class="btn btn-primary dropdown-toggle" aria-controls="dropdown-basic">
Actions <span class="caret"></span>
</button>
<ul id="dropdown-basic" *dropdownMenu class="dropdown-menu" role="menu" aria-labelledby="button-basic">
<li *ngIf="getConfigDownloadResultFormat('download_csv')" role="menuitem">
<a class="dropdown-item" [href]="getUrl('csv')" (click)="click($event, getUrl('csv'), 'csv')">
<span class="fas fa-file-csv"></span> Download CSV
</a>
</li>
<li *ngIf="getConfigDownloadResultFormat('download_ascii')" role="menuitem">
<a class="dropdown-item" [href]="getUrl('ascii')" (click)="click($event, getUrl('ascii'), 'txt')">
<span class="fas fa-file"></span> Download ASCII
</a>
</li>
<li *ngIf="getConfigDownloadResultFormat('download_vo')" role="menuitem">
<a class="dropdown-item" [href]="getUrl('votable')" (click)="click($event, getUrl('votable'), 'xml')">
<span class="fas fa-file"></span> VOtable
</a>
</li>
<li *ngIf="getConfigDownloadResultFormat('download_vo')" role="menuitem">
<a class="dropdown-item" (click)="broadcastVotable()">
<span class="fas fa-broadcast-tower"></span> Broadcast VOtable
</a>
</li>
<li *ngIf="getConfigDownloadResultFormat('download_archive')" role="menuitem">
<a class="dropdown-item" [href]="getUrlArchive()" (click)="click($event, getUrlArchive(), 'zip')">
<span class="fas fa-archive"></span> Download files archive
</a>
</li>
</ul>
</div>
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Dataset, Attribute } from 'src/app/metamodel/models';
import { Criterion, ConeSearch, criterionToString } from 'src/app/instance/store/models';
import { getHost } from 'src/app/shared/utils';
import { AppConfigService } from 'src/app/app-config.service';
@Component({
selector: 'app-datatable-actions',
templateUrl: 'datatable-actions.component.html'
})
export class DatatableActionsComponent {
@Input() selectedData: any[] = [];
@Input() datasetSelected: string;
@Input() datasetList: Dataset[];
@Input() attributeList: Attribute[];
@Input() criteriaList: Criterion[];
@Input() outputList: number[];
@Input() coneSearch: ConeSearch;
@Input() dataLength: number;
@Input() sampRegistered: boolean;
@Output() broadcast: EventEmitter<string> = new EventEmitter();
constructor(private appConfig: AppConfigService, private http: HttpClient) { }
/**
* Checks if the download format is allowed by Anis Admin configuration.
*
* @param {string} format - The file format to download.
*
* @return boolean
*/
getConfigDownloadResultFormat(format: string): boolean {
const dataset = this.datasetList.find(d => d.name === this.datasetSelected);
return dataset.config.download[format];
}
/**
* Returns URL to download file for the given format.
*
* @param {string} format - The file format to download.
*
* @return string
*/
getUrl(format: string): string {
let query: string = `${getHost(this.appConfig.apiUrl)}/search/${this.datasetSelected}?a=${this.outputList.join(';')}`;
if (this.criteriaList.length > 0) {
query += `&c=${this.criteriaList.map(criterion => criterionToString(criterion)).join(';')};${this.getCriterionSelectedData()}`;
} else {
query += `&c=${this.getCriterionSelectedData()}`;
}
if (this.coneSearch) {
query += `&cs=${this.coneSearch.ra}:${this.coneSearch.dec}:${this.coneSearch.radius}`;
}
query += `&f=${format}`;
return query;
}
getCriterionSelectedData() {
const attributeId = this.attributeList.find(a => a.search_flag === 'ID');
return `${attributeId.id}::in::${this.selectedData.join('|')}`;
}
/**
* Returns URL to download archive.
*
* @return boolean
*/
getUrlArchive(): string {
let query: string = `${getHost(this.appConfig.apiUrl)}/archive/${this.datasetSelected}?a=${this.outputList.join(';')}`;
if (this.criteriaList.length > 0) {
query += `&c=${this.criteriaList.map(criterion => criterionToString(criterion)).join(';')};${this.getCriterionSelectedData()}`;
} else {
query += `&c=${this.getCriterionSelectedData()}`;
}
if (this.coneSearch) {
query += `&cs=${this.coneSearch.ra}:${this.coneSearch.dec}:${this.coneSearch.radius}`;
}
return query;
}
/**
* Emits event to action to broadcast data.
*
* @fires EventEmitter<string>
*/
broadcastVotable(): void {
this.broadcast.emit(this.getUrl('votable'));
}
/**
* Allows to download file.
*/
click(event, href, extension): void {
event.preventDefault();
this.http.get(href, {responseType: "blob"}).subscribe(
data => {
let downloadLink = document.createElement('a');
downloadLink.href = window.URL.createObjectURL(data);
downloadLink.setAttribute('download', `${this.datasetSelected}.${extension}`);
downloadLink.click();
}
);
}
}
...@@ -8,6 +8,18 @@ ...@@ -8,6 +8,18 @@
<span *ngIf="!ag.isOpen"><span class="fas fa-chevron-down"></span></span> <span *ngIf="!ag.isOpen"><span class="fas fa-chevron-down"></span></span>
</span> </span>
</button> </button>
<app-datatable-actions
[selectedData]="selectedData"
[datasetSelected]="datasetSelected"
[datasetList]="datasetList"
[attributeList]="attributeList"
[criteriaList]="criteriaList"
[outputList]="outputList"
[coneSearch]="coneSearch"
[dataLength]="dataLength"
[sampRegistered]="sampRegistered"
(broadcast)="broadcast.emit($event)">
</app-datatable-actions>
<app-datatable <app-datatable
[dataset]="datasetList | datasetByName:datasetSelected" [dataset]="datasetList | datasetByName:datasetSelected"
[instance]="instance" [instance]="instance"
......
...@@ -6,7 +6,7 @@ import { AccordionModule } from 'ngx-bootstrap/accordion'; ...@@ -6,7 +6,7 @@ import { AccordionModule } from 'ngx-bootstrap/accordion';
import { DatatableTabComponent } from './datatable-tab.component'; import { DatatableTabComponent } from './datatable-tab.component';
import { Attribute, Dataset, Instance } from '../../../../metamodel/models'; import { Attribute, Dataset, Instance } from '../../../../metamodel/models';
import { SearchQueryParams } from '../../../store/models'; import { SearchQueryParams, Criterion, ConeSearch } from '../../../store/models';
import { DatasetByNamePipe } from '../../../../shared/pipes/dataset-by-name.pipe'; import { DatasetByNamePipe } from '../../../../shared/pipes/dataset-by-name.pipe';
describe('[Instance][Search][Component][Result] DatatableTabComponent', () => { describe('[Instance][Search][Component][Result] DatatableTabComponent', () => {
...@@ -24,6 +24,19 @@ describe('[Instance][Search][Component][Result] DatatableTabComponent', () => { ...@@ -24,6 +24,19 @@ describe('[Instance][Search][Component][Result] DatatableTabComponent', () => {
@Input() selectedData: any[] = []; @Input() selectedData: any[] = [];
} }
@Component({ selector: 'app-datatable-actions', template: '' })
class DatatableActionsStubComponent {
@Input() selectedData: any[] = [];
@Input() datasetSelected: string;
@Input() datasetList: Dataset[];
@Input() attributeList: Attribute[];
@Input() criteriaList: Criterion[];
@Input() outputList: number[];
@Input() coneSearch: ConeSearch;
@Input() dataLength: number;
@Input() sampRegistered: boolean;
}
let component: DatatableTabComponent; let component: DatatableTabComponent;
let fixture: ComponentFixture<DatatableTabComponent>; let fixture: ComponentFixture<DatatableTabComponent>;
...@@ -32,6 +45,7 @@ describe('[Instance][Search][Component][Result] DatatableTabComponent', () => { ...@@ -32,6 +45,7 @@ describe('[Instance][Search][Component][Result] DatatableTabComponent', () => {
declarations: [ declarations: [
DatatableTabComponent, DatatableTabComponent,
DatatableStubComponent, DatatableStubComponent,
DatatableActionsStubComponent,
DatasetByNamePipe DatasetByNamePipe
], ],
imports: [ imports: [
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { Instance, Attribute, Dataset } from 'src/app/metamodel/models'; import { Instance, Attribute, Dataset } from 'src/app/metamodel/models';
import { Pagination, SearchQueryParams } from 'src/app/instance/store/models'; import { Pagination, SearchQueryParams, Criterion, ConeSearch } from 'src/app/instance/store/models';
/** /**
* @class * @class
...@@ -27,8 +27,11 @@ export class DatatableTabComponent { ...@@ -27,8 +27,11 @@ export class DatatableTabComponent {
@Input() datasetList: Dataset[]; @Input() datasetList: Dataset[];
@Input() attributeList: Attribute[]; @Input() attributeList: Attribute[];
@Input() outputList: number[]; @Input() outputList: number[];
@Input() criteriaList: Criterion[];
@Input() coneSearch: ConeSearch;
@Input() queryParams: SearchQueryParams; @Input() queryParams: SearchQueryParams;
@Input() dataLength: number; @Input() dataLength: number;
@Input() sampRegistered: boolean;
@Input() data: any[]; @Input() data: any[];
@Input() dataIsLoading: boolean; @Input() dataIsLoading: boolean;
@Input() dataIsLoaded: boolean; @Input() dataIsLoaded: boolean;
...@@ -36,4 +39,5 @@ export class DatatableTabComponent { ...@@ -36,4 +39,5 @@ export class DatatableTabComponent {
@Output() retrieveData: EventEmitter<Pagination> = new EventEmitter(); @Output() retrieveData: EventEmitter<Pagination> = new EventEmitter();
@Output() addSelectedData: EventEmitter<number | string> = new EventEmitter(); @Output() addSelectedData: EventEmitter<number | string> = new EventEmitter();
@Output() deleteSelectedData: EventEmitter<number | string> = new EventEmitter(); @Output() deleteSelectedData: EventEmitter<number | string> = new EventEmitter();
@Output() broadcast: EventEmitter<string> = new EventEmitter();
} }
...@@ -4,6 +4,7 @@ import { ReminderComponent } from './reminder.component'; ...@@ -4,6 +4,7 @@ import { ReminderComponent } from './reminder.component';
import { SampComponent } from './samp.component'; import { SampComponent } from './samp.component';
import { UrlDisplayComponent } from './url-display.component'; import { UrlDisplayComponent } from './url-display.component';
import { DatatableComponent } from './datatable.component'; import { DatatableComponent } from './datatable.component';
import { DatatableActionsComponent } from './datatable-actions.component';
import { rendererComponents } from './renderer'; import { rendererComponents } from './renderer';
export const resultComponents = [ export const resultComponents = [
...@@ -13,5 +14,6 @@ export const resultComponents = [ ...@@ -13,5 +14,6 @@ export const resultComponents = [
SampComponent, SampComponent,
UrlDisplayComponent, UrlDisplayComponent,
DatatableComponent, DatatableComponent,
DatatableActionsComponent,
rendererComponents rendererComponents
]; ];
...@@ -65,16 +65,19 @@ ...@@ -65,16 +65,19 @@
[instance]="instance | async" [instance]="instance | async"
[datasetList]="datasetList | async" [datasetList]="datasetList | async"
[attributeList]="attributeList | async | sortByOutputDisplay" [attributeList]="attributeList | async | sortByOutputDisplay"
[criteriaList]="criteriaList | async"
[outputList]="outputList | async" [outputList]="outputList | async"
[queryParams]="queryParams | async" [queryParams]="queryParams | async"
[dataLength]="dataLength | async" [dataLength]="dataLength | async"
[sampRegistered]="sampRegistered | async"
[data]="data | async" [data]="data | async"
[dataIsLoading]="dataIsLoading | async" [dataIsLoading]="dataIsLoading | async"
[dataIsLoaded]="dataIsLoaded | async" [dataIsLoaded]="dataIsLoaded | async"
[selectedData]="selectedData | async" [selectedData]="selectedData | async"
(retrieveData)="retrieveData($event)" (retrieveData)="retrieveData($event)"
(addSelectedData)="addSearchData($event)" (addSelectedData)="addSearchData($event)"
(deleteSelectedData)="deleteSearchData($event)"> (deleteSelectedData)="deleteSearchData($event)"
(broadcast)="broadcastVotable($event)">
</app-datatable-tab> </app-datatable-tab>
</ng-container> </ng-container>
</div> </div>
......
...@@ -66,8 +66,11 @@ describe('[Instance][Search][Container] ResultComponent', () => { ...@@ -66,8 +66,11 @@ describe('[Instance][Search][Container] ResultComponent', () => {
@Input() datasetList: Dataset[]; @Input() datasetList: Dataset[];
@Input() attributeList: Attribute[]; @Input() attributeList: Attribute[];
@Input() outputList: number[]; @Input() outputList: number[];
@Input() criteriaList: Criterion[];
@Input() coneSearch: ConeSearch;
@Input() queryParams: SearchQueryParams; @Input() queryParams: SearchQueryParams;
@Input() dataLength: number; @Input() dataLength: number;
@Input() sampRegistered: boolean;
@Input() data: any[]; @Input() data: any[];
@Input() dataIsLoading: boolean; @Input() dataIsLoading: boolean;
@Input() dataIsLoaded: boolean; @Input() dataIsLoaded: boolean;
......
...@@ -51,6 +51,7 @@ import { sharedPipes } from './pipes'; ...@@ -51,6 +51,7 @@ import { sharedPipes } from './pipes';
CommonModule, CommonModule,
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
BsDropdownModule,
ModalModule, ModalModule,
AccordionModule, AccordionModule,
PopoverModule, PopoverModule,
......
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