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

Refactor result page => done

parent 2626c373
No related branches found
No related tags found
2 merge requests!72Develop,!34New features
Showing
with 216 additions and 394 deletions
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"@ngrx/store-devtools": "13.0.2", "@ngrx/store-devtools": "13.0.2",
"bootstrap": "4.6.1", "bootstrap": "4.6.1",
"d3": "^5.15.1", "d3": "^5.15.1",
"file-saver": "^2.0.5",
"keycloak-angular": "^9.1.0", "keycloak-angular": "^9.1.0",
"keycloak-js": "^16.1.1", "keycloak-js": "^16.1.1",
"ngx-bootstrap": "^8.0.0", "ngx-bootstrap": "^8.0.0",
...@@ -40,6 +41,7 @@ ...@@ -40,6 +41,7 @@
"@angular/cli": "~13.2.3", "@angular/cli": "~13.2.3",
"@angular/compiler-cli": "~13.2.2", "@angular/compiler-cli": "~13.2.2",
"@types/d3": "^5.7.2", "@types/d3": "^5.7.2",
"@types/file-saver": "^2.0.5",
"@types/jasmine": "~3.10.0", "@types/jasmine": "~3.10.0",
"@types/jest": "^27.4.0", "@types/jest": "^27.4.0",
"@types/node": "^12.11.1", "@types/node": "^12.11.1",
...@@ -49,4 +51,4 @@ ...@@ -49,4 +51,4 @@
"jest-preset-angular": "^11.1.0", "jest-preset-angular": "^11.1.0",
"typescript": "~4.5.5" "typescript": "~4.5.5"
} }
} }
\ No newline at end of file
...@@ -15,7 +15,7 @@ import * as searchMultiple from './store/reducers/search-multiple.reducer'; ...@@ -15,7 +15,7 @@ import * as searchMultiple from './store/reducers/search-multiple.reducer';
import * as coneSearch from './store/reducers/cone-search.reducer'; import * as coneSearch from './store/reducers/cone-search.reducer';
import * as detail from './store/reducers/detail.reducer'; import * as detail from './store/reducers/detail.reducer';
import * as svomJsonKw from './store/reducers/svom-json-kw.reducer'; import * as svomJsonKw from './store/reducers/svom-json-kw.reducer';
import * as downloadFile from './store/reducers/download-file.reducer'; import * as archive from './store/reducers/archive.reducer';
/** /**
* Interface for instance state. * Interface for instance state.
...@@ -28,7 +28,7 @@ export interface State { ...@@ -28,7 +28,7 @@ export interface State {
coneSearch: coneSearch.State coneSearch: coneSearch.State
detail: detail.State, detail: detail.State,
svomJsonKw: svomJsonKw.State, svomJsonKw: svomJsonKw.State,
downloadFile: downloadFile.State archive: archive.State
} }
const reducers = { const reducers = {
...@@ -37,7 +37,7 @@ const reducers = { ...@@ -37,7 +37,7 @@ const reducers = {
coneSearch: coneSearch.coneSearchReducer, coneSearch: coneSearch.coneSearchReducer,
detail: detail.detailReducer, detail: detail.detailReducer,
svomJsonKw: svomJsonKw.svomJsonKwReducer, svomJsonKw: svomJsonKw.svomJsonKwReducer,
downloadFile: downloadFile.fileReducer archive: archive.archiveReducer
}; };
export const instanceReducer = combineReducers(reducers); export const instanceReducer = combineReducers(reducers);
......
import { Directive, Input, Output, EventEmitter } from '@angular/core';
import { Dataset } from 'src/app/metamodel/models';
import { Criterion, ConeSearch, criterionToString } from 'src/app/instance/store/models';
import { AppConfigService } from 'src/app/app-config.service';
import { getHost } from 'src/app/shared/utils';
@Directive()
export abstract class AbstractDownloadComponent {
@Input() dataset: Dataset;
@Input() criteriaList: Criterion[];
@Input() outputList: number[];
@Input() coneSearch: ConeSearch;
@Input() archiveIsCreating: boolean;
@Output() downloadFile: EventEmitter<{url: string, filename: string}> = new EventEmitter();
constructor(private appConfig: AppConfigService) { }
/**
* Returns API URL to get data with user parameters.
*
* @return string
*/
getUrl(format: string, selectedData: string = null): string {
return `${getHost(this.appConfig.apiUrl)}/search/${this.getQuery(selectedData)}&f=${format}`;
}
getQuery(selectedData: string = null) {
let query = `${this.dataset.name}?a=${this.outputList.join(';')}`;
if (this.criteriaList.length > 0) {
query += `&c=${this.criteriaList.map(criterion => criterionToString(criterion)).join(';')}`;
if (selectedData) {
query += `;${selectedData}`;
}
} else if (selectedData) {
query += `&c=${selectedData}`;
}
if (this.coneSearch) {
query += `&cs=${this.coneSearch.ra}:${this.coneSearch.dec}:${this.coneSearch.radius}`;
}
return query;
}
download(event, url: string, format: string) {
event.preventDefault();
const timeElapsed = Date.now();
const today = new Date(timeElapsed);
const filename = `result_${this.dataset.name}_${today.toISOString()}.${this.formatToExtension(format)}`;
this.downloadFile.emit({ url, filename });
}
formatToExtension(format: string) {
let extension: string;
switch (format) {
case 'json': {
extension = 'json';
break;
}
case 'csv': {
extension = 'csv';
break;
}
case 'ascii': {
extension = 'txt';
break;
}
case 'votable': {
extension = 'xml';
break;
}
default: {
extension = 'json';
break;
}
}
return extension;
}
}
\ No newline at end of file
<div id="plot" class="row bg-light"></div> <div id="plot" class="row justify-content-center"></div>
\ No newline at end of file \ No newline at end of file
...@@ -7,13 +7,12 @@ ...@@ -7,13 +7,12 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
import { Component, Input, ChangeDetectionStrategy, ViewEncapsulation, OnInit, SimpleChanges } from '@angular/core'; import { Component, Input, ChangeDetectionStrategy, ViewEncapsulation, OnInit } from '@angular/core';
import * as d3 from 'd3'; import * as d3 from 'd3';
import { Dataset, Image } from 'src/app/metamodel/models'; import { Dataset } from 'src/app/metamodel/models';
import { ConeSearch } from 'src/app/instance/store/models'; import { ConeSearch } from 'src/app/instance/store/models';
import { AppConfigService } from 'src/app/app-config.service';
/** /**
* @class * @class
...@@ -30,7 +29,7 @@ export class ConeSearchPlotComponent implements OnInit { ...@@ -30,7 +29,7 @@ export class ConeSearchPlotComponent implements OnInit {
@Input() coneSearch: ConeSearch; @Input() coneSearch: ConeSearch;
@Input() dataset: Dataset; @Input() dataset: Dataset;
@Input() data: {x: number, y: number}[]; @Input() data: {x: number, y: number}[];
@Input() selectedBackground: Image; @Input() backgroundHref: string;
// Interactive variables intialisation // Interactive variables intialisation
margin = { top: 50, right: 50, bottom: 50 , left: 50 }; margin = { top: 50, right: 50, bottom: 50 , left: 50 };
...@@ -41,42 +40,10 @@ export class ConeSearchPlotComponent implements OnInit { ...@@ -41,42 +40,10 @@ export class ConeSearchPlotComponent implements OnInit {
x: d3.ScaleLinear<number, number>; x: d3.ScaleLinear<number, number>;
y: d3.ScaleLinear<number, number>; y: d3.ScaleLinear<number, number>;
constructor(private config: AppConfigService) { }
ngOnInit(): void { ngOnInit(): void {
this.coneSearchPlot(); this.coneSearchPlot();
} }
ngOnChanges(changes: SimpleChanges) {
if (changes.selectedBackground && changes.selectedBackground.currentValue) {
console.log('coucou');
this.image.attr('xlink:href', this.getHrefBackgroundImage());
}
}
getHrefBackgroundImage() {
if (this.selectedBackground) {
let href = `${this.config.servicesUrl}/fits-cut-to-png/${this.dataset.name}?filename=${this.selectedBackground.file_path}`;
href += `&ra=${this.coneSearch.ra}`;
href += `&dec=${this.coneSearch.dec}`;
href += `&radius=${this.coneSearch.radius}`;
href += `&stretch=${this.selectedBackground.stretch}`;
href += `&pmin=${this.selectedBackground.pmin}`;
href += `&pmax=${this.selectedBackground.pmax}`;
href += `&axes=false`;
return href;
} else {
const scale = this.coneSearch.radius / this.width; // arcsec/pix
return `https://skyserver.sdss.org/dr16/SkyServerWS/ImgCutout/getjpeg?TaskName=Skyserver.Chart.Image
&ra=${this.coneSearch.ra}
&dec=${this.coneSearch.dec}
&scale=${scale}
&width=${this.width}
&height=${this.height}`;
}
}
coneSearchPlot(): void { coneSearchPlot(): void {
// Init SVG // Init SVG
const svg = d3.select('#plot').append('svg') const svg = d3.select('#plot').append('svg')
...@@ -93,7 +60,7 @@ export class ConeSearchPlotComponent implements OnInit { ...@@ -93,7 +60,7 @@ export class ConeSearchPlotComponent implements OnInit {
// Background image // Background image
this.image = svg.append('image'); this.image = svg.append('image');
this.image.attr('xlink:href', this.getHrefBackgroundImage()) this.image.attr('xlink:href', this.backgroundHref)
.attr('width', this.width) .attr('width', this.width)
.attr('height', this.height); .attr('height', this.height);
......
<div *ngIf="getDataset().datatable_selectable_rows" class="btn-group mb-2" dropdown [isDisabled]="selectedData.length < 1"> <div *ngIf="dataset.datatable_selectable_rows" 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"> <button id="button-basic" dropdownToggle type="button" class="btn btn-primary dropdown-toggle" aria-controls="dropdown-basic">
Actions <span class="caret"></span> Actions <span class="caret"></span>
</button> </button>
<ul id="dropdown-basic" *dropdownMenu class="dropdown-menu" role="menu" aria-labelledby="button-basic"> <ul id="dropdown-basic" *dropdownMenu class="dropdown-menu" role="menu" aria-labelledby="button-basic">
<li *ngIf="getConfigDownloadResultFormat('download_csv')" role="menuitem"> <li *ngIf="dataset.download_json" role="menuitem">
<a class="dropdown-item" (click)="downloadResult('csv')"> <a class="dropdown-item" [href]="getDatatableUrl('json')" (click)="download($event, getDatatableUrl('json'), 'json')">
<span class="fas fa-file"></span> Download JSON
</a>
</li>
<li *ngIf="dataset.download_csv" role="menuitem">
<a class="dropdown-item" [href]="getDatatableUrl('csv')" (click)="download($event, getDatatableUrl('csv'), 'csv')">
<span class="fas fa-file-csv"></span> Download CSV <span class="fas fa-file-csv"></span> Download CSV
</a> </a>
</li> </li>
<li *ngIf="getConfigDownloadResultFormat('download_ascii')" role="menuitem"> <li *ngIf="dataset.download_ascii" role="menuitem">
<a class="dropdown-item" (click)="downloadResult('ascii')"> <a class="dropdown-item" [href]="getDatatableUrl('ascii')" (click)="download($event, getDatatableUrl('ascii'), 'ascii')">
<span class="fas fa-file"></span> Download ASCII <span class="fas fa-file"></span> Download ASCII
</a> </a>
</li> </li>
<li *ngIf="getConfigDownloadResultFormat('download_vo')" role="menuitem"> <li *ngIf="dataset.download_vo" role="menuitem">
<a class="dropdown-item" (click)="downloadResult('votable')"> <a class="dropdown-item" [href]="getDatatableUrl('votable')" (click)="download($event, getDatatableUrl('votable'), 'votable')">
<span class="fas fa-file"></span> VOtable <span class="fas fa-file"></span> VOtable
</a> </a>
</li> </li>
<li *ngIf="getConfigDownloadResultFormat('download_vo')" role="menuitem" [class.disabled]="!sampRegistered"> <li *ngIf="dataset.download_vo" role="menuitem" [class.disabled]="!sampRegistered">
<a class="dropdown-item" [class.disabled]="!sampRegistered" (click)="broadcastResult()"> <a class="dropdown-item" [class.disabled]="!sampRegistered" (click)="broadcastResult()">
<span class="fas fa-broadcast-tower"></span> Broadcast VOtable <span class="fas fa-broadcast-tower"></span> Broadcast VOtable
</a> </a>
</li> </li>
<li *ngIf="getConfigDownloadResultFormat('download_archive')" role="menuitem"> <li *ngIf="isArchiveIsAvailable()" role="menuitem" [class.disabled]="archiveIsCreating">
<a class="dropdown-item" (click)="downloadArchive()"> <a class="dropdown-item" [class.disabled]="archiveIsCreating" (click)="downloadArchive()">
<span class="fas fa-archive"></span> Download files archive <span class="fas fa-archive"></span> Download files archive
</a> </a>
</li> </li>
......
import { Component, Input, Output, EventEmitter } from '@angular/core'; import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Dataset } from 'src/app/metamodel/models'; import { AbstractDownloadComponent } from './abstract-download.component';
import { Attribute } from 'src/app/metamodel/models';
@Component({ @Component({
selector: 'app-datatable-actions', selector: 'app-datatable-actions',
templateUrl: 'datatable-actions.component.html' templateUrl: 'datatable-actions.component.html'
}) })
export class DatatableActionsComponent { export class DatatableActionsComponent extends AbstractDownloadComponent {
@Input() attributeList: Attribute[];
@Input() selectedData: any[] = []; @Input() selectedData: any[] = [];
@Input() datasetSelected: string;
@Input() datasetList: Dataset[];
@Input() sampRegistered: boolean; @Input() sampRegistered: boolean;
@Output() startTaskCreateResult: EventEmitter<{ format: string, selectedData: boolean, broadcastVo: boolean }> = new EventEmitter(); @Output() broadcastVotable: EventEmitter<string> = new EventEmitter();
@Output() startTaskCreateArchive: EventEmitter<{ selectedData: boolean }> = new EventEmitter(); @Output() startTaskCreateArchive: EventEmitter<string> = new EventEmitter();
/** isArchiveIsAvailable() {
* Checks if the download format is allowed by Anis Admin configuration. return this.attributeList
* .filter(attribute => this.outputList.includes(attribute.id))
* @param {string} format - The file format to download. .filter(attribute => attribute.archive)
* .length > 0;
* @return boolean
*/
getConfigDownloadResultFormat(format: string): boolean {
return this.getDataset()[format];
} }
getDataset() { getDatatableUrl(format: string): string {
return this.datasetList.find(d => d.name === this.datasetSelected); const attributeId = this.attributeList.find(a => a.primary_key);
return this.getUrl(format, `${attributeId.id}::in::${this.selectedData.join('|')}`);
} }
downloadResult(format: string) {
this.startTaskCreateResult.emit({
format,
selectedData: true,
broadcastVo: false
});
}
broadcastResult() { broadcastResult() {
this.startTaskCreateResult.emit({ const url = this.getDatatableUrl('votable');
format: 'votable', this.broadcastVotable.emit(url);
selectedData: true,
broadcastVo: true
})
} }
downloadArchive() { downloadArchive() {
this.startTaskCreateArchive.emit({ const attributeId = this.attributeList.find(a => a.primary_key);
selectedData: true this.startTaskCreateArchive.emit(this.getQuery(`${attributeId.id}::in::${this.selectedData.join('|')}`));
});
} }
} }
<accordion *ngIf="(datasetList | datasetByName:datasetSelected).datatable_enabled" [isAnimated]="true">
<accordion-group #ag [isOpen]="(datasetList | datasetByName:datasetSelected).datatable_opened" [panelClass]="'custom-accordion'" class="my-2">
<button class="btn btn-link btn-block clearfix" accordion-heading>
<span class="pull-left float-left">
Display result details
&nbsp;
<span *ngIf="ag.isOpen"><span class="fas fa-chevron-up"></span></span>
<span *ngIf="!ag.isOpen"><span class="fas fa-chevron-down"></span></span>
</span>
</button>
<div class="row">
<div class="col-md-5" *ngIf="coneSearch">
<div class="form-group">
<label for="file_size">Background image</label>
<ng-select [(ngModel)]="selectedBackground">
<ng-option *ngFor="let image of imageList" [value]="image">{{ image.file_path }}</ng-option>
</ng-select>
</div>
<app-cone-search-plot *ngIf="dataIsLoaded"
[coneSearch]="coneSearch"
[dataset]="datasetList | datasetByName:datasetSelected"
[data]="getData()"
[selectedBackground]="selectedBackground">
</app-cone-search-plot>
</div>
<div class="datatable-group" [ngClass]="{'col': !coneSearch, 'col-md-7' : coneSearch }">
<div class="row">
<div class="col">
<app-datatable-actions
[selectedData]="selectedData"
[datasetSelected]="datasetSelected"
[datasetList]="datasetList"
[sampRegistered]="sampRegistered"
(broadcast)="broadcast.emit($event)"
(startTaskCreateResult)="startTaskCreateResult.emit($event)"
(startTaskCreateArchive)="startTaskCreateArchive.emit($event)">
</app-datatable-actions>
<app-datatable
[dataset]="datasetList | datasetByName:datasetSelected"
[instance]="instance"
[attributeList]="attributeList"
[outputList]="outputList"
[queryParams]="queryParams"
[dataLength]="dataLength"
[data]="data"
[dataIsLoading]="dataIsLoading"
[dataIsLoaded]="dataIsLoaded"
[selectedData]="selectedData"
(retrieveData)="retrieveData.emit($event)"
(addSelectedData)="addSelectedData.emit($event)"
(deleteSelectedData)="deleteSelectedData.emit($event)"
(downloadFile)="downloadFile.emit($event)">
</app-datatable>
</div>
</div>
</div>
</div>
</accordion-group>
</accordion>
.datatable-group > .row {
overflow-x: auto;
white-space: nowrap;
}
.datatable-group > .row > .col {
display: inline-block;
float: none;
}
\ No newline at end of file
import { Component, Input } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AccordionModule } from 'ngx-bootstrap/accordion';
import { DatatableTabComponent } from './datatable-tab.component';
import { Attribute, Dataset, Instance } from '../../../../metamodel/models';
import { SearchQueryParams, Criterion, ConeSearch } from '../../../store/models';
import { DatasetByNamePipe } from '../../../../shared/pipes/dataset-by-name.pipe';
describe('[Instance][Search][Component][Result] DatatableTabComponent', () => {
@Component({ selector: 'app-datatable', template: '' })
class DatatableStubComponent {
@Input() dataset: Dataset;
@Input() instance: Instance;
@Input() attributeList: Attribute[];
@Input() outputList: number[];
@Input() queryParams: SearchQueryParams;
@Input() dataLength: number;
@Input() data: any[];
@Input() dataIsLoading: boolean;
@Input() dataIsLoaded: boolean;
@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 fixture: ComponentFixture<DatatableTabComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
DatatableTabComponent,
DatatableStubComponent,
DatatableActionsStubComponent,
DatasetByNamePipe
],
imports: [
AccordionModule.forRoot(),
BrowserAnimationsModule
]
});
fixture = TestBed.createComponent(DatatableTabComponent);
component = fixture.componentInstance;
});
it('should create the component', () => {
expect(component).toBeTruthy();
});
});
/**
* 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 { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { Instance, Attribute, Dataset, Image } from 'src/app/metamodel/models';
import { Pagination, SearchQueryParams, Criterion, ConeSearch } from 'src/app/instance/store/models';
/**
* @class
* @classdesc Search result datatable tab component.
*/
@Component({
selector: 'app-datatable-tab',
templateUrl: 'datatable-tab.component.html',
styleUrls: [ 'datatable-tab.component.scss' ],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DatatableTabComponent {
@Input() datasetSelected: string;
@Input() instance: Instance;
@Input() datasetList: Dataset[];
@Input() attributeList: Attribute[];
@Input() outputList: number[];
@Input() criteriaList: Criterion[];
@Input() coneSearch: ConeSearch;
@Input() queryParams: SearchQueryParams;
@Input() dataLength: number;
@Input() sampRegistered: boolean;
@Input() data: any[];
@Input() dataIsLoading: boolean;
@Input() dataIsLoaded: boolean;
@Input() selectedData: any[];
@Input() imageList: Image[];
@Input() imageListIsLoading: boolean;
@Input() imageListIsLoaded: boolean;
@Output() retrieveData: EventEmitter<Pagination> = new EventEmitter();
@Output() addSelectedData: EventEmitter<number | string> = new EventEmitter();
@Output() deleteSelectedData: EventEmitter<number | string> = new EventEmitter();
@Output() broadcast: EventEmitter<string> = new EventEmitter();
@Output() startTaskCreateResult: EventEmitter<{ format: string, selectedData: boolean, broadcastVo: boolean }> = new EventEmitter();
@Output() startTaskCreateArchive: EventEmitter<{ selectedData: boolean }> = new EventEmitter();
@Output() downloadFile: EventEmitter<{url: string, fileId: string, datasetName: string, filename: string}> = new EventEmitter();
selectedBackground: Image = null;
getData() {
const dataset = this.getDataset();
const columnRa = this.attributeList.find(a => a.id === dataset.cone_search_column_ra);
const columnDec = this.attributeList.find(a => a.id === dataset.cone_search_column_dec);
return this.data.map(d => ({ "x": +d[columnRa.label], "y": +d[columnDec.label] }));
}
/**
* Returns selected dataset for the search.
*
* @return Dataset
*/
getDataset(): Dataset {
return this.datasetList.find(dataset => dataset.name === this.datasetSelected);
}
}
...@@ -7,11 +7,6 @@ ...@@ -7,11 +7,6 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
.table-responsive {
overflow-y: scroll;
height: 650px;
}
table th:not(.select) { table th:not(.select) {
min-width: 130px; min-width: 130px;
} }
......
...@@ -44,7 +44,7 @@ export class DatatableComponent implements OnInit { ...@@ -44,7 +44,7 @@ export class DatatableComponent implements OnInit {
@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() downloadFile: EventEmitter<{url: string, fileId: string, datasetName: string, filename: string}> = new EventEmitter(); @Output() downloadFile: EventEmitter<{url: string, filename: string}> = new EventEmitter();
public page = 1; public page = 1;
public nbItems = 10; public nbItems = 10;
......
<div class="jumbotron mb-4 py-4">
<div class="lead">
Files downloaded :
<ul>
<li *ngFor="let downloadFile of downloadedFiles">
{{ downloadFile.fileName }} :
<ng-container *ngIf="downloadFile.state == 'PENDING'">
<br>
<span class="fas fa-circle-notch fa-spin"></span>
<span class="sr-only">Loading...</span>
</ng-container>
<progressbar [value]="downloadFile.progress" [type]="getType(downloadFile.progress)" [animate]="true">{{ downloadFile.progress }}%</progressbar>
</li>
</ul>
</div>
</div>
\ No newline at end of file
/**
* 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 } from '@angular/core';
import { DownloadFile } from 'src/app/instance/store/models';
/**
* @class
* @classdesc Search result reminder component.
*/
@Component({
selector: 'app-download-file-tab',
templateUrl: 'download-file-tab.component.html',
styleUrls: ['download-file-tab.component.scss']
})
export class DownloadFileTabComponent {
@Input() downloadedFiles: DownloadFile[];
getType(value: number): 'success' | 'info' {
if (value < 100) {
return 'info';
}
return 'success';
}
}
<table>
<tr>
<th>Download results </th>
<td>
<a *ngIf="dataset.download_json" [href]="getUrl('json')" (click)="download($event, getUrl('json'), 'json')" class="btn btn-primary" title="Download results in JSON format">
<span class="fas fa-file"></span> JSON
</a>
&nbsp;
<a *ngIf="dataset.download_csv" [href]="getUrl('csv')" (click)="download($event, getUrl('csv'), 'csv')" class="btn btn-primary" title="Download results in CSV format">
<span class="fas fa-file-csv"></span> CSV
</a>
&nbsp;
<a *ngIf="dataset.download_ascii" [href]="getUrl('ascii')" (click)="download($event, getUrl('ascii'), 'ascii')" class="btn btn-primary" title="Download results in ASCII format">
<span class="fas fa-file"></span> ASCII
</a>
&nbsp;
<a *ngIf="dataset.download_vo" [href]="getUrl('votable')" (click)="download($event, getUrl('votable'), 'votable')" class="btn btn-primary" title="Download results in VO format">
<span class="fas fa-file"></span> VOtable
</a>
</td>
</tr>
<tr *ngIf="isArchiveIsAvailable()">
<th>Download files </th>
<td>
<a [class.disabled]="archiveIsCreating" (click)="downloadArchive()" class="btn btn-primary" title="Download an archive with all files">
<span class="fas fa-archive"></span> Files archive
</a>
</td>
</tr>
<tr *ngIf="instance.samp_enabled">
<th>VO-SAMP </th>
<td>
<button *ngIf="!sampRegistered" (click)="sampRegister.emit()" class="btn btn-primary">Try to register</button>
<button *ngIf="sampRegistered" (click)="sampUnregister.emit()" class="btn btn-danger">SAMP Unregister</button>
&nbsp;
<button *ngIf="sampRegistered && dataset.download_vo" (click)="broadcastResult()" class="btn btn-primary" title="Broadcast samp votable">
<span class="fas fa-broadcast-tower"></span> Broadcast VOtable
</button>
</td>
</tr>
</table>
<p *ngIf="archiveIsCreating" class="text-center mt-2 text-danger font-weight-bold">
Archive is under construction ! Please stay on this page
<span class="fas fa-circle-notch fa-spin fa-2x"></span>
<span class="sr-only">Loading...</span>
</p>
\ No newline at end of file
th {
font-weight: normal;
width: 200px;
}
tr {
height: 50px;
}
\ No newline at end of file
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { AbstractDownloadComponent } from './abstract-download.component';
import { Instance, Attribute } from 'src/app/metamodel/models';
@Component({
selector: 'app-download-result',
templateUrl: 'download-result.component.html',
styleUrls: ['download-result.component.scss']
})
export class DownloadResultComponent extends AbstractDownloadComponent{
@Input() instance: Instance;
@Input() attributeList: Attribute[];
@Input() sampRegistered: boolean;
@Output() sampRegister: EventEmitter<{}> = new EventEmitter();
@Output() sampUnregister: EventEmitter<{}> = new EventEmitter();
@Output() broadcastVotable: EventEmitter<string> = new EventEmitter();
@Output() startTaskCreateArchive: EventEmitter<string> = new EventEmitter();
isArchiveIsAvailable() {
return this.attributeList
.filter(attribute => this.outputList.includes(attribute.id))
.filter(attribute => attribute.archive)
.length > 0;
}
broadcastResult() {
const url = this.getUrl('votable');
this.broadcastVotable.emit(url);
}
downloadArchive() {
this.startTaskCreateArchive.emit(this.getQuery());
}
}
\ No newline at end of file
<accordion *ngIf="isDownloadActivated()" [isAnimated]="true">
<accordion-group #ag [isOpen]="isDownloadOpened()" [panelClass]="'custom-accordion'" class="my-2">
<button class="btn btn-link btn-block clearfix" accordion-heading>
<span class="pull-left float-left">
Download results
&nbsp;
<span *ngIf="ag.isOpen">
<span class="fas fa-chevron-up"></span>
</span>
<span *ngIf="!ag.isOpen">
<span class="fas fa-chevron-down"></span>
</span>
</span>
</button>
<div>
<div class="row">
<div class="col-auto align-self-center">
<p>Download results just here:</p>
</div>
<div class="col">
<a *ngIf="getConfigDownloadResultFormat('download_json')" (click)="downloadResult('json')" class="btn btn-outline-primary" title="Download results in JSON format">
<span class="fas fa-file"></span> JSON
</a>
&nbsp;
<a *ngIf="getConfigDownloadResultFormat('download_csv')" (click)="downloadResult('csv')" class="btn btn-outline-primary" title="Download results in CSV format">
<span class="fas fa-file-csv"></span> CSV
</a>
&nbsp;
<a *ngIf="getConfigDownloadResultFormat('download_ascii')" (click)="downloadResult('ascii')" class="btn btn-outline-primary" title="Download results in ASCII format">
<span class="fas fa-file"></span> ASCII
</a>
&nbsp;
<a *ngIf="getConfigDownloadResultFormat('download_vo')" (click)="downloadResult('votable')" class="btn btn-outline-primary" title="Download results in VO format">
<span class="fas fa-file"></span> VOtable
</a>
&nbsp;
<button *ngIf="getConfigDownloadResultFormat('download_vo')" [disabled]="!sampRegistered" (click)="broadcastResult()" class="btn btn-outline-primary" title="Broadcast samp votable">
<span class="fas fa-broadcast-tower"></span> Broadcast VOtable
</button>
</div>
</div>
<hr *ngIf="isArchiveIsAvailable()" class="my-4">
<div *ngIf="isArchiveIsAvailable()" class="row">
<div class="col-auto align-self-center">
<p>Download archive files just here:</p>
</div>
<div class="col">
<a (click)="downloadArchive()" class="btn btn-outline-primary" title="Download an archive with all files">
<span class="fas fa-archive"></span> Files archive
</a>
</div>
</div>
</div>
</accordion-group>
</accordion>
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