Skip to content
Snippets Groups Projects
Commit 77ebba24 authored by Tifenn Guillas's avatar Tifenn Guillas
Browse files

WIP: Move datatable component

parent 73852a4a
No related branches found
No related tags found
2 merge requests!147Develop,!137Resolve "[Module Multiple] : ajouter le nouveau module"
Showing
with 773 additions and 36 deletions
...@@ -4,6 +4,7 @@ import { Attribute } from '../model'; ...@@ -4,6 +4,7 @@ import { Attribute } from '../model';
export const LOAD_ATTRIBUTE_SEARCH_META = '[Attribute] Load Attribute Search Meta'; export const LOAD_ATTRIBUTE_SEARCH_META = '[Attribute] Load Attribute Search Meta';
export const LOAD_ATTRIBUTE_SEARCH_META_SUCCESS = '[Attribute] Load Attribute Search Meta Success'; export const LOAD_ATTRIBUTE_SEARCH_META_SUCCESS = '[Attribute] Load Attribute Search Meta Success';
export const LOAD_ATTRIBUTE_SEARCH_MULTIPLE_META_SUCCESS = '[Attribute] Load Attribute Search Multiple Meta Success';
export const LOAD_ATTRIBUTE_SEARCH_META_FAIL = '[Attribute] Load Attribute Search Meta Fail'; export const LOAD_ATTRIBUTE_SEARCH_META_FAIL = '[Attribute] Load Attribute Search Meta Fail';
export class LoadAttributeSearchMetaAction implements Action { export class LoadAttributeSearchMetaAction implements Action {
...@@ -18,6 +19,12 @@ export class LoadAttributeSearchMetaSuccessAction implements Action { ...@@ -18,6 +19,12 @@ export class LoadAttributeSearchMetaSuccessAction implements Action {
constructor(public payload: Attribute[]) { } constructor(public payload: Attribute[]) { }
} }
export class LoadAttributeSearchMultipleMetaSuccessAction implements Action {
readonly type = LOAD_ATTRIBUTE_SEARCH_MULTIPLE_META_SUCCESS;
constructor(public payload: Attribute[]) { }
}
export class LoadAttributeSearchMetaFailAction implements Action { export class LoadAttributeSearchMetaFailAction implements Action {
readonly type = LOAD_ATTRIBUTE_SEARCH_META_FAIL; readonly type = LOAD_ATTRIBUTE_SEARCH_META_FAIL;
...@@ -27,4 +34,5 @@ export class LoadAttributeSearchMetaFailAction implements Action { ...@@ -27,4 +34,5 @@ export class LoadAttributeSearchMetaFailAction implements Action {
export type Actions export type Actions
= LoadAttributeSearchMetaAction = LoadAttributeSearchMetaAction
| LoadAttributeSearchMetaSuccessAction | LoadAttributeSearchMetaSuccessAction
| LoadAttributeSearchMultipleMetaSuccessAction
| LoadAttributeSearchMetaFailAction; | LoadAttributeSearchMetaFailAction;
...@@ -3,30 +3,50 @@ import { Injectable } from '@angular/core'; ...@@ -3,30 +3,50 @@ import { Injectable } from '@angular/core';
import { ToastrService } from 'ngx-toastr'; import { ToastrService } from 'ngx-toastr';
import { Effect, Actions, ofType } from '@ngrx/effects'; import { Effect, Actions, ofType } from '@ngrx/effects';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { switchMap, map, catchError, tap } from 'rxjs/operators'; import { switchMap, map, catchError, tap, withLatestFrom } from 'rxjs/operators';
import { Attribute } from '../model'; import { Attribute } from '../model';
import * as attributeActions from '../action/attribute.action'; import * as attributeActions from '../action/attribute.action';
import { AttributeService } from '../services/attribute.service'; import { AttributeService } from '../services/attribute.service';
import { Store } from "@ngrx/store";
import * as fromRouter from "@ngrx/router-store";
import * as utils from "../../shared/utils";
import * as fromSearch from "../../search/store/search.reducer";
import * as fromMetamodel from "../reducers";
import * as fromConeSearch from "../../shared/cone-search/store/cone-search.reducer";
@Injectable() @Injectable()
export class AttributeEffects { export class AttributeEffects {
constructor( constructor(
private actions$: Actions, private actions$: Actions,
private attributeService: AttributeService, private attributeService: AttributeService,
private toastr: ToastrService private toastr: ToastrService,
private store$: Store<{
router: fromRouter.RouterReducerState<utils.RouterStateUrl>,
search: fromSearch.State,
metamodel: fromMetamodel.State,
coneSearch: fromConeSearch.State
}>
) { } ) { }
@Effect() @Effect()
loadAttributeSearchMetaAction$ = this.actions$.pipe( loadAttributeSearchMetaAction$ = this.actions$.pipe(
ofType(attributeActions.LOAD_ATTRIBUTE_SEARCH_META), ofType(attributeActions.LOAD_ATTRIBUTE_SEARCH_META),
switchMap((action: attributeActions.LoadAttributeSearchMetaAction) => withLatestFrom(this.store$),
this.attributeService.retrieveAttributeSearchMeta(action.payload).pipe( switchMap(([action, state]) => {
map((attributeList: Attribute[]) => const loadAttributeSearchMetaAction = action as attributeActions.LoadAttributeSearchMetaAction;
new attributeActions.LoadAttributeSearchMetaSuccessAction(attributeList)), return this.attributeService.retrieveAttributeSearchMeta(loadAttributeSearchMetaAction.payload).pipe(
map((attributeList: Attribute[]) => {
const module: string = state.router.state.url.split('/')[1];
if (module === 'search') {
new attributeActions.LoadAttributeSearchMetaSuccessAction(attributeList)
} else {
new attributeActions.LoadAttributeSearchMultipleMetaSuccessAction(attributeList)
}
}),
catchError(() => of(new attributeActions.LoadAttributeSearchMetaFailAction())) catchError(() => of(new attributeActions.LoadAttributeSearchMetaFailAction()))
) )
) })
); );
@Effect({ dispatch: false }) @Effect({ dispatch: false })
......
...@@ -4,6 +4,8 @@ import { DatasetListComponent } from './datasets/dataset-list.component'; ...@@ -4,6 +4,8 @@ import { DatasetListComponent } from './datasets/dataset-list.component';
import { DatasetsByProjetComponent } from './datasets/datasets-by-projet.component'; import { DatasetsByProjetComponent } from './datasets/datasets-by-projet.component';
import { OverviewComponent } from './result/overview.component'; import { OverviewComponent } from './result/overview.component';
import { DatasetsResultComponent } from './result/datasets-result.component'; import { DatasetsResultComponent } from './result/datasets-result.component';
import { DatatableComponent } from "../../shared/datatable/datatable.component";
import { RendererComponents } from "../../shared/datatable/renderer";
export const dummiesComponents = [ export const dummiesComponents = [
ProgressBarMultipleComponent, ProgressBarMultipleComponent,
...@@ -11,5 +13,7 @@ export const dummiesComponents = [ ...@@ -11,5 +13,7 @@ export const dummiesComponents = [
DatasetListComponent, DatasetListComponent,
DatasetsByProjetComponent, DatasetsByProjetComponent,
OverviewComponent, OverviewComponent,
DatasetsResultComponent DatasetsResultComponent,
DatatableComponent,
RendererComponents
]; ];
\ No newline at end of file
<div *ngIf="datasetsCountIsLoaded"> <div *ngIf="datasetsCountIsLoaded">
<accordion [isAnimated]="true"> <accordion [isAnimated]="true">
<ng-container *ngFor="let dataset of getOrderedDatasetWithResults()"> <ng-container *ngFor="let dataset of getOrderedDatasetWithResults()">
<accordion-group (isOpenChange)="retrieveData.emit(dataset.name)" #ag [panelClass]="'custom-accordion'" [isOpen]="false" class="my-2"> <accordion-group (isOpenChange)="retrieveMeta.emit(dataset.name)" #ag [panelClass]="'custom-accordion'" [isOpen]="false" class="my-2">
<button class="btn btn-link btn-block clearfix" accordion-heading> <button class="btn btn-link btn-block clearfix" accordion-heading>
<div class="pull-left float-left"> <div class="pull-left float-left">
{{ dataset.label }} <span class="badge badge-pill badge-primary">{{ getCount(dataset.name) }}</span> {{ dataset.label }} <span class="badge badge-pill badge-primary">{{ getCount(dataset.name) }}</span>
...@@ -14,27 +14,18 @@ ...@@ -14,27 +14,18 @@
</span> </span>
</div> </div>
</button> </button>
toto <!-- <app-datatable-->
<!-- [dataset]="dataset"-->
<!-- [datasetAttributeList]="getDatasetAttributeList(dataset.name)"-->
<!-- [outputList]="outputList"-->
<!-- [data]="data"-->
<!-- [dataLength]="getCount(dataset.name)"-->
<!-- (getData)="getData(dataset.name, $event)"-->
<!-- (addSelectedData)="addSelectedData($event)"-->
<!-- (deleteSelectedData)="deleteSelectedData($event)"-->
<!-- (executeProcess)="executeProcess($event)">-->
<!-- </app-datatable>-->
</accordion-group> </accordion-group>
</ng-container> </ng-container>
</accordion> </accordion>
</div> </div>
\ No newline at end of file
<!-- <app-result-datatable-->
<!-- [datasetName]="datasetName | async"-->
<!-- [datasetList]="datasetList | async"-->
<!-- [queryParams]="queryParams | async"-->
<!-- [datasetAttributeList]="datasetAttributeList | async"-->
<!-- [outputList]="outputList | async"-->
<!-- [searchData]="searchData | async"-->
<!-- [dataLength]="dataLength | async"-->
<!-- [selectedData]="selectedData | async"-->
<!-- (getSearchData)="getSearchData($event)"-->
<!-- (addSelectedData)="addSearchData($event)"-->
<!-- (deleteSelectedData)="deleteSearchData($event)"-->
<!-- [processWip]="processWip | async"-->
<!-- [processDone]="processDone | async"-->
<!-- [processId]="processId | async"-->
<!-- (executeProcess)="executeProcess($event)">-->
<!-- </app-result-datatable>-->
\ No newline at end of file
import {Component, Input, Output, ChangeDetectionStrategy, EventEmitter} from '@angular/core'; import { Component, Input, Output, ChangeDetectionStrategy, EventEmitter } from '@angular/core';
import { Dataset, Project } from "../../../metamodel/model"; import { Attribute, Dataset, Project } from "../../../metamodel/model";
import { DatasetCount } from "../../store/model"; import { DatasetCount } from "../../store/model";
import {sortByDisplay} from "../../../shared/utils"; import { sortByDisplay } from "../../../shared/utils";
@Component({ @Component({
selector: 'app-datasets-result', selector: 'app-datasets-result',
...@@ -14,7 +14,10 @@ export class DatasetsResultComponent { ...@@ -14,7 +14,10 @@ export class DatasetsResultComponent {
@Input() projectList: Project[]; @Input() projectList: Project[];
@Input() datasetList: Dataset[]; @Input() datasetList: Dataset[];
@Input() selectedDatasets: string[]; @Input() selectedDatasets: string[];
// TODO: change any type
@Input() datasetsAttributeList: any;
@Input() datasetsCount: DatasetCount[]; @Input() datasetsCount: DatasetCount[];
@Output() retrieveMeta: EventEmitter<string> = new EventEmitter();
@Output() retrieveData: EventEmitter<string> = new EventEmitter(); @Output() retrieveData: EventEmitter<string> = new EventEmitter();
getOrderedDatasetWithResults(): Dataset[] { getOrderedDatasetWithResults(): Dataset[] {
...@@ -37,4 +40,24 @@ export class DatasetsResultComponent { ...@@ -37,4 +40,24 @@ export class DatasetsResultComponent {
getCount(dname: string): number { getCount(dname: string): number {
return this.datasetsCount.find(c => c.dname === dname).count; return this.datasetsCount.find(c => c.dname === dname).count;
} }
// getDatasetAttributeList(dname: string): Attribute[] {
//
// }
getData(dname: string, pagination: any): void {
console.log(dname, pagination);
}
addSelectedData(d: number | string): void {
console.log('addSelectedData: ' + d);
}
deleteSelectedData(d: number | string): void {
console.log('deleteSelectedData: ' + d);
}
executeProcess(typeProcess: string): void {
console.log('executeProcess: ' + typeProcess);
}
} }
\ No newline at end of file
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
[datasetList]="datasetList | async" [datasetList]="datasetList | async"
[selectedDatasets]="selectedDatasets | async" [selectedDatasets]="selectedDatasets | async"
[datasetsCount]="datasetsCount | async" [datasetsCount]="datasetsCount | async"
(retrieveData)="retrieveData($event)"> (retrieveMeta)="retrieveMeta($event)">
</app-datasets-result> </app-datasets-result>
</div> </div>
</div> </div>
......
...@@ -8,6 +8,7 @@ import { Attribute, Dataset, Project } from '../../metamodel/model'; ...@@ -8,6 +8,7 @@ import { Attribute, Dataset, Project } from '../../metamodel/model';
import { ConeSearch } from "../../shared/cone-search/store/model"; import { ConeSearch } from "../../shared/cone-search/store/model";
import * as searchMultipleActions from '../store/search-multiple.action'; import * as searchMultipleActions from '../store/search-multiple.action';
import * as datasetActions from '../../metamodel/action/dataset.action'; import * as datasetActions from '../../metamodel/action/dataset.action';
import * as attributeActions from '../../metamodel/action/attribute.action';
import * as fromSearchMultiple from '../store/search-multiple.reducer'; import * as fromSearchMultiple from '../store/search-multiple.reducer';
import * as fromMetamodel from '../../metamodel/reducers'; import * as fromMetamodel from '../../metamodel/reducers';
import * as searchMultipleSelector from '../store/search-multiple.selector'; import * as searchMultipleSelector from '../store/search-multiple.selector';
...@@ -77,8 +78,8 @@ export class ResultMultipleComponent implements OnInit, OnDestroy { ...@@ -77,8 +78,8 @@ export class ResultMultipleComponent implements OnInit, OnDestroy {
this.store.dispatch(new searchMultipleActions.RetrieveDatasetsCountAction()); this.store.dispatch(new searchMultipleActions.RetrieveDatasetsCountAction());
} }
retrieveData(dname: string): void { retrieveMeta(dname: string): void {
console.log(dname); this.store.dispatch(new attributeActions.LoadAttributeSearchMetaAction(dname));
} }
// getSearchData(pagination: [number, number, number, string]): void { // getSearchData(pagination: [number, number, number, string]): void {
......
...@@ -20,6 +20,7 @@ import * as datasetActions from "../../metamodel/action/dataset.action"; ...@@ -20,6 +20,7 @@ import * as datasetActions from "../../metamodel/action/dataset.action";
import {Attribute, Dataset, Family, Project} from "../../metamodel/model"; import {Attribute, Dataset, Family, Project} from "../../metamodel/model";
import * as searchActions from "../../search/store/search.action"; import * as searchActions from "../../search/store/search.action";
import * as documentationActions from "../../documentation/store/documentation.action"; import * as documentationActions from "../../documentation/store/documentation.action";
import * as attributeActions from "../../metamodel/action/attribute.action";
@Injectable() @Injectable()
export class SearchMultipleEffects { export class SearchMultipleEffects {
...@@ -122,6 +123,117 @@ export class SearchMultipleEffects { ...@@ -122,6 +123,117 @@ export class SearchMultipleEffects {
tap(_ => this.toastr.error('Loading Failed!', 'The data count of datasets loading failed')) tap(_ => this.toastr.error('Loading Failed!', 'The data count of datasets loading failed'))
); );
@Effect()
loadDatasetAttributeListSuccessAction$ = this.actions$.pipe(
ofType(attributeActions.LOAD_ATTRIBUTE_SEARCH_MULTIPLE_META_SUCCESS),
withLatestFrom(this.store$),
switchMap(([action, state]) => {
const loadAttributeSearchMultipleMetaSuccessAction = action as attributeActions.LoadAttributeSearchMultipleMetaSuccessAction;
console.log('MODULE MULTIPLE');
return of();
// const actions: Action[] = [];
//
// let defaultOutputList = loadAttributeSearchMetaSuccessAction.payload
// .filter(attribute => attribute.selected && attribute.id_output_category)
// .sort((a, b) => a.output_display - b.output_display)
// .map(attribute => attribute.id);
//
// if (state.router.state.queryParams.a) {
// defaultOutputList = state.router.state.queryParams.a.split(';').map((o: string) => parseInt(o, 10));
// }
//
// actions.push(new searchActions.UpdateOutputListAction(defaultOutputList));
//
// let defaultCriteriaList = loadAttributeSearchMetaSuccessAction.payload
// .filter(attribute => attribute.id_criteria_family && attribute.search_type && attribute.min)
// .map(attribute => {
// switch (attribute.search_type) {
// case 'field':
// case 'select':
// case 'datalist':
// case 'radio':
// case 'date':
// case 'date-time':
// case 'time':
// return { id: attribute.id, type: 'field', value: attribute.min.toString(), operator: attribute.operator };
// case 'list':
// return { id: attribute.id, type: 'list', values: attribute.min.toString().split('|') };
// case 'between':
// case 'between-date':
// return { id: attribute.id, type: 'between', min: attribute.min.toString(), max: attribute.max.toString() };
// case 'select-multiple':
// case 'checkbox':
// const msValues = attribute.min.toString().split('|');
// const options = attribute.options.filter(option => msValues.includes(option.value));
// return { id: attribute.id, type: 'multiple', options };
// case 'json':
// const [path, operator, value] = attribute.min.toString().split('|');
// return { id: attribute.id, type: 'json', path, operator, value };
//
// default:
// return null;
// }
// });
//
// if (state.router.state.queryParams.c) {
// defaultCriteriaList = state.router.state.queryParams.c.split(';').map((c: string) => {
// const params = c.split('::');
// const attribute = loadAttributeSearchMetaSuccessAction.payload.find(a => a.id === parseInt(params[0], 10));
// switch (attribute.search_type) {
// case 'field':
// case 'select':
// case 'datalist':
// case 'radio':
// case 'date':
// case 'date-time':
// case 'time':
// return { id: parseInt(params[0], 10), type: 'field', operator: params[1], value: params[2] };
// case 'list':
// return { id: parseInt(params[0], 10), type: 'list', values: params[2].split('|') };
// case 'between':
// case 'between-date':
// if (params[1] === 'bw') {
// const bwValues = params[2].split('|');
// return { id: parseInt(params[0], 10), type: 'between', min: bwValues[0], max: bwValues[1] };
// } else if (params[1] === 'gte') {
// return { id: parseInt(params[0], 10), type: 'between', min: params[2], max: null };
// } else {
// return { id: parseInt(params[0], 10), type: 'between', min: null, max: params[2] };
// }
// case 'select-multiple':
// case 'checkbox':
// const msValues = params[2].split('|');
// const options = attribute.options.filter(option => msValues.includes(option.value));
// return { id: parseInt(params[0], 10), type: 'multiple', options };
// case 'json':
// const [path, operator, value] = params[2].split('|');
// return { id: parseInt(params[0], 10), type: 'json', path, operator, value };
//
// default:
// return null;
// }
// });
// }
//
// actions.push(new searchActions.UpdateCriteriaListAction(defaultCriteriaList));
//
// if (state.router.state.queryParams.cs) {
// const params = state.router.state.queryParams.cs.split(':');
// const coneSearch: ConeSearch = {
// ra: parseFloat(params[0]),
// dec: parseFloat(params[1]),
// radius: parseInt(params[2], 10)
// };
// actions.push(new searchActions.IsConeSearchAddedAction(true));
// actions.push(new coneSearchActions.AddConeSearchAction(coneSearch));
// }
//
// return actions;
})
);
// @Effect() // @Effect()
// retrieveDataAction$ = this.actions$.pipe( // retrieveDataAction$ = this.actions$.pipe(
// ofType(searchMultipleActions.RETRIEVE_DATA), // ofType(searchMultipleActions.RETRIEVE_DATA),
......
.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;
}
<div *ngIf="!dataLength || !outputList || !datasetAttributeList || !data" class="text-center">
<span class="fas fa-circle-notch fa-spin fa-3x"></span>
<span class="sr-only">Loading...</span>
</div>
<div *ngIf="dataLength && outputList && datasetAttributeList && data">
<div *ngIf="dataset.selectable_row" class="mb-2">
<button [disabled]="noSelectedData() || processWip" (click)="emitProcess('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.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-sort-amount-down-alt"></span>
</span>
<span [ngClass]="{'active': sortedOrder === 'd', 'inactive': sortedOrder === 'a'}">
<span class="fas fa-sort-amount-up"></span>
</span>
</span>
<span *ngIf="attribute.id !== sortedCol" class="pl-2">
<span class="unsorted">
<span class="fas fa-arrows-alt-v"></span>
</span>
<span class="on-hover">
<span class="fas fa-sort-amount-down-alt"></span>
</span>
</span>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let datum of data">
<td *ngIf="dataset.selectable_row" class="data-selected"
(click)="toggleSelection(datum)">
<button class="btn btn-block text-left p-0 m-0">
<div *ngIf="!isSelected(datum)">
<span class="far fa-square fa-lg text-secondary"></span>
</div>
<div *ngIf="isSelected(datum)">
<span class="fas fa-check-square fa-lg theme-color"></span>
</div>
</button>
</td>
<td *ngFor="let attribute of getOutputList()" class="align-middle">
<div *ngIf="datum[attribute.label]" [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
[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>
\ No newline at end of file
// import { ComponentFixture, TestBed } from '@angular/core/testing';
// import { Component, Input } from '@angular/core';
// import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
//
// import { AccordionModule } from 'ngx-bootstrap/accordion';
// import { DatatableSectionComponent } from './datatable.component';
// import { Dataset } from '../../../metamodel/model';
// import { ATTRIBUTE_LIST, DATASET_LIST } from '../../../../settings/test-data';
//
// describe('[Search][Result] Component: DatatableComponent', () => {
// @Component({ selector: 'app-img', template: '' })
// class ImgStubComponent {
// @Input() src: string;
// }
//
// @Component({ selector: 'app-thumbnail', template: '' })
// class ThumbnailStubComponent {
// @Input() src: string;
// @Input() attributeName: string;
// }
//
// @Component({ selector: 'app-link', template: '' })
// class LinkStubComponent {
// @Input() href: string;
// }
//
// @Component({ selector: 'app-btn', template: '' })
// class BtnStubComponent {
// @Input() href: string;
// }
//
// @Component({ selector: 'app-detail', template: '' })
// class DetailStubComponent {
// @Input() style: string;
// @Input() datasetName: string;
// @Input() data: string | number;
// }
//
// @Component({ selector: 'app-download', template: '' })
// class DownloadStubComponent {
// @Input() href: string;
// }
//
// @Component({ selector: 'app-json-renderer', template: '' })
// class JsonStubComponent {
// @Input() attributeName: string;
// @Input() json: string;
// }
//
// @Component({ selector: 'pagination', template: '' })
// class PaginationStubComponent {
// @Input() totalItems: number;
// @Input() boundaryLinks: boolean;
// @Input() rotate: boolean;
// @Input() maxSize: number;
// }
//
// let component: DatatableSectionComponent;
// let fixture: ComponentFixture<DatatableSectionComponent>;
//
// beforeEach(() => {
// TestBed.configureTestingModule({
// declarations: [
// DatatableSectionComponent,
// ImgStubComponent,
// ThumbnailStubComponent,
// LinkStubComponent,
// BtnStubComponent,
// DetailStubComponent,
// DownloadStubComponent,
// JsonStubComponent,
// PaginationStubComponent
// ],
// imports: [AccordionModule.forRoot(), BrowserAnimationsModule]
// });
// fixture = TestBed.createComponent(DatatableSectionComponent);
// component = fixture.componentInstance;
// });
//
// it('should create the component', () => {
// expect(component).toBeTruthy();
// });
//
// it('#isDatatableOpened() should return if datatable has to be opened or not', () => {
// component.datasetList = DATASET_LIST;
// component.datasetName = 'cat_1';
// expect(component.isDatatableOpened()).toBeTruthy();
// component.datasetName = 'cat_2';
// expect(component.isDatatableOpened()).toBeFalsy();
// });
//
// it('#getOutputList() should return filtered output list', () => {
// component.outputList = [2]
// component.datasetAttributeList = ATTRIBUTE_LIST;
// expect(component.getOutputList().length).toBe(1);
// });
//
// it('#getDataset() should return dataset object', () => {
// component.datasetList = DATASET_LIST;
// component.datasetName = 'cat_1';
// const dataset: Dataset = component.getDataset();
// expect(dataset.name).toBe('cat_1');
// expect(dataset.label).toBe('Cat 1');
// });
//
// it('#getAttributeId(attributeName) should return id of attributeName', () => {
// component.datasetAttributeList = ATTRIBUTE_LIST;
// expect(component.getAttributeId('name_one')).toBe(1);
// });
//
// it('#toggleSelection(datum) should return add datum to selectedData', () => {
// const datum = { label_one: 123456 };
// component.datasetAttributeList = ATTRIBUTE_LIST;
// component.selectedData = [];
// component.addSelectedData.subscribe((event: any) => expect(event).toBe(123456));
// component.toggleSelection(datum);
// });
//
// it('#toggleSelection(datum) should return remove datum to selectedData', () => {
// const datum = { label_one: 123456 };
// component.selectedData = [123456];
// component.datasetAttributeList = ATTRIBUTE_LIST;
// component.deleteSelectedData.subscribe((event: any) => expect(event).toBe(123456));
// component.toggleSelection(datum);
// });
//
// it('#isSelected(datum) should return true datum is selected', () => {
// const datum = { label_one: 123456 };
// component.datasetAttributeList = ATTRIBUTE_LIST;
// component.selectedData = [123456];
// expect(component.isSelected(datum)).toBeTruthy();
// });
//
// it('#isSelected(datum) should return false datum is not selected', () => {
// const datum = { label_one: 123456 };
// component.datasetAttributeList = ATTRIBUTE_LIST;
// component.selectedData = [];
// expect(component.isSelected(datum)).toBeFalsy();
// });
//
// it('#noSelectedData() should return true if no selectedData', () => {
// component.selectedData = [];
// expect(component.noSelectedData()).toBeTruthy();
// });
//
// it('#noSelectedData() should return false if there are selectedData', () => {
// component.selectedData = [123456];
// expect(component.noSelectedData()).toBeFalsy();
// });
//
// it('#emitProcess() should raise executeProcess event and transmit process type', () => {
// component.executeProcess.subscribe((event: string) => expect(event).toBe('test'));
// component.emitProcess('test');
// });
//
// it('#changePage() should change page value and raise getSearchData event', () => {
// component.sortedCol = 1;
// component.sortedOrder = 'a';
// component.getSearchData.subscribe((event: [number, number, number, string]) => expect(event).toEqual([2, 10, 1, 'a']));
// component.changePage(2);
// });
//
// it('#changeNbItems() should change nbItems value and raise getSearchData event', () => {
// component.sortedCol = 1;
// component.sortedOrder = 'a';
// component.getSearchData.subscribe((event: [number, number, number, string]) => expect(event).toEqual([1, 20, 1, 'a']));
// component.changeNbItems(20);
// });
//
// it('#ngOnInit() should init sortedCol and sortedOrder values', () => {
// component.datasetAttributeList = ATTRIBUTE_LIST;
// component.ngOnInit();
// expect(component.sortedCol).toEqual(1);
// expect(component.sortedOrder).toBe('a');
// });
//
// it('#sort() should raise getSearchData event with correct parameters', () => {
// component.sortedOrder = 'a';
// let subscribtion = component.getSearchData.subscribe((event: [number, number, number, string]) => expect(event).toEqual([1, 10, 1, 'a']));
// component.sort(1);
// subscribtion.unsubscribe();
// component.sortedCol = 1;
// component.sortedOrder = 'a';
// subscribtion = component.getSearchData.subscribe((event: [number, number, number, string]) => expect(event).toEqual([1, 10, 1, 'd']));
// component.sort(1);
// subscribtion.unsubscribe();
// component.sortedCol = 1;
// component.sortedOrder = 'd';
// subscribtion = component.getSearchData.subscribe((event: [number, number, number, string]) => expect(event).toEqual([1, 10, 1, 'a']));
// component.sort(1);
// });
// });
//
import { Component, Input, ChangeDetectionStrategy, Output, EventEmitter, ViewEncapsulation, OnInit } from '@angular/core';
// import { SearchQueryParams } from '../../store/model';
import { Attribute, Dataset } from 'src/app/metamodel/model';
@Component({
selector: 'app-datatable',
templateUrl: 'datatable.component.html',
styleUrls: ['datatable.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
})
export class DatatableComponent implements OnInit {
@Input() dataset: Dataset;
// @Input() queryParams: SearchQueryParams;
@Input() datasetAttributeList: 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<[number, number, number, string]> = 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: string = null;
ngOnInit() {
this.sortedCol = this.datasetAttributeList.find(a => a.search_flag === 'ID').id;
this.sortedOrder = 'a';
this.getData.emit([this.page, this.nbItems, this.sortedCol, this.sortedOrder]);
}
getOutputList(): Attribute[] {
return this.datasetAttributeList
.filter(a => this.outputList.includes(a.id))
.sort((a, b) => a.output_display - b.output_display);
}
getAttributeId(attributeName: string): number {
const attribute = this.datasetAttributeList.find(a => a.name === attributeName);
return attribute.id;
}
toggleSelection(datum: any): void {
const attribute = this.datasetAttributeList.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]);
}
}
isSelected(datum: any): boolean {
const attribute = this.datasetAttributeList.find(a => a.search_flag === 'ID');
if (this.selectedData.indexOf(datum[attribute.label]) > -1) {
return true;
}
return false;
}
noSelectedData(): boolean {
return this.selectedData.length < 1;
}
emitProcess(typeProcess: string): void {
this.executeProcess.emit(typeProcess);
}
changePage(nb: number): void {
this.page = nb;
this.getData.emit([this.page, this.nbItems, this.sortedCol, this.sortedOrder]);
}
changeNbItems(nb: number): void {
this.nbItems = nb;
this.getData.emit([this.page, this.nbItems, this.sortedCol, this.sortedOrder]);
}
sort(id: number): void {
if (id === this.sortedCol) {
this.sortedOrder = this.sortedOrder === 'a' ? 'd' : 'a';
} else {
this.sortedCol = id;
this.sortedOrder = 'a';
}
this.getData.emit([this.page, this.nbItems, this.sortedCol, this.sortedOrder]);
}
}
<a routerLink="/detail/{{ datasetName }}/{{ value }}" [target]="config.blank == true ? '_blank' : '_self'"
[ngClass]="{'btn btn-outline-primary btn-sm' : config.display == 'text-button'}">
{{ value }}
</a>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { DetailComponent } from './detail.component';
describe('[Search][Result][Renderer] Component: DetailComponent', () => {
let component: DetailComponent;
let fixture: ComponentFixture<DetailComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [DetailComponent],
imports: [RouterTestingModule]
});
fixture = TestBed.createComponent(DetailComponent);
component = fixture.componentInstance;
});
it('should create the component', () => {
expect(component).toBeTruthy();
});
});
import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
import { RendererConfig } from "../../../metamodel/model";
interface DetailConfig extends RendererConfig {
display: string;
blank: boolean;
}
@Component({
selector: 'app-detail',
templateUrl: 'detail.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DetailComponent {
@Input() value: string | number;
@Input() datasetName: string;
@Input() config: DetailConfig;
}
<a [href]="getHref()" [ngClass]="{'btn btn-outline-primary btn-sm': (config.display=='text-button' || config.display=='icon-button')}">
<span *ngIf="config.display !== 'icon-button'">{{ config.text }}</span>
<span *ngIf="config.display === 'icon-button'" class="{{config.icon}}"></span>
</a>
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DownloadComponent } from './download.component';
import { environment } from "../../../../../environments/environment";
describe('[Search][Result][Renderer] Component: DownloadComponent', () => {
let component: DownloadComponent;
let fixture: ComponentFixture<DownloadComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [DownloadComponent]
});
fixture = TestBed.createComponent(DownloadComponent);
component = fixture.componentInstance;
});
it('should create the component', () => {
expect(component).toBeTruthy();
});
it('#getHref() should return file url', () => {
component.datasetName = 'dname';
component.value = 'val';
expect(component.getHref()).toBe(environment.apiUrl + '/download-file/dname/val');
});
});
import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
import { RendererConfig } from '../../../metamodel/model';
import { getHost } from "../../utils";
interface LinkConfig extends RendererConfig {
display: string;
text: string;
icon: string;
}
@Component({
selector: 'app-download',
templateUrl: 'download.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DownloadComponent {
@Input() value: string;
@Input() datasetName: string;
@Input() config: LinkConfig;
getHref(): string {
return getHost() + '/download-file/' + this.datasetName + '/' + this.value;
}
}
<img [src]="getValue()" [alt]="getValue()">
\ No newline at end of file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ImageComponent } from './image.component';
import { environment } from "../../../../../environments/environment";
describe('[Search][Result][Renderer] Component: ImageComponent', () => {
let component: ImageComponent;
let fixture: ComponentFixture<ImageComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ImageComponent]
});
fixture = TestBed.createComponent(ImageComponent);
component = fixture.componentInstance;
});
it('should create the component', () => {
expect(component).toBeTruthy();
});
it('#getValue() should return image url', () => {
component.datasetName = 'dname';
component.value = 'val';
expect(component.getValue()).toEqual(environment.apiUrl + '/download-file/dname/val');
});
});
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