diff --git a/src/app/detail/components/default-object.component.ts b/src/app/detail/components/default-object.component.ts index b60270a9849ba50af4115ba1169b5f9b4b7836d8..8e7775e2de09798aa6a8dca94118787f8060a2ee 100644 --- a/src/app/detail/components/default-object.component.ts +++ b/src/app/detail/components/default-object.component.ts @@ -16,6 +16,10 @@ import { Attribute, Category, Family } from '../../metamodel/model'; templateUrl: 'default-object.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) +/** + * @class + * @classdesc Detail default object component. + */ export class DefaultObjectComponent { @Input() datasetName: string; @Input() outputFamilyList: Family[]; diff --git a/src/app/detail/components/object-data.component.ts b/src/app/detail/components/object-data.component.ts index 8dd46aea3afeb4a455fddf018cfa32219a277289..309b550cff764b03e11c9fa7dff27cb0b8370fb5 100644 --- a/src/app/detail/components/object-data.component.ts +++ b/src/app/detail/components/object-data.component.ts @@ -10,12 +10,17 @@ import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { Attribute, Category, Family } from '../../metamodel/model'; +import { sortByDisplay } from '../../shared/utils'; @Component({ selector: 'app-object-data', templateUrl: 'object-data.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) +/** + * @class + * @classdesc Detail object data component. + */ export class ObjectDataComponent { @Input() datasetName: string; @Input() outputFamilyList: Family[]; @@ -23,12 +28,26 @@ export class ObjectDataComponent { @Input() attributeList: Attribute[]; @Input() object: any; + /** + * Returns category list sorted by display, for the given output family ID. + * + * @param {number} idFamily - The output family ID. + * + * @return Category[] + */ getCategoryByFamilySortedByDisplay(idFamily: number): Category[] { return this.categoryList .filter(category => category.id_output_family === idFamily) - .sort((a, b) => a.display - b.display); + .sort(sortByDisplay); } + /** + * Returns attribute list sorted by detail display, for the given output category ID. + * + * @param {number} idCategory - The output category ID. + * + * @return Attribute[] + */ getAttributesVisibleByCategory(idCategory: number): Attribute[] { return this.attributeList .filter(a => a.detail) @@ -36,12 +55,24 @@ export class ObjectDataComponent { .sort((a, b) => a.display_detail - b.display_detail); } + /** + * Returns attribute list sorted by detail display. + * + * @return Attribute[] + */ getAttributesVisible(): Attribute[] { return this.attributeList .filter(a => a.detail) .sort((a, b) => a.display_detail - b.display_detail); } + /** + * Returns attribute for the given search flag. + * + * @param {string} searchFlag - The search flag. + * + * @return Attribute + */ getAttributeBySearchFlag(searchFlag: string): Attribute { return this.getAttributesVisible().find(attribute => attribute.search_flag === searchFlag); } diff --git a/src/app/detail/components/spectra/spectra-object.component.ts b/src/app/detail/components/spectra/spectra-object.component.ts index 00f4426182601ff66a555ce11199218e49a17375..09db7fb6f6244b0db34bb9015a62b30c47de0936 100644 --- a/src/app/detail/components/spectra/spectra-object.component.ts +++ b/src/app/detail/components/spectra/spectra-object.component.ts @@ -18,6 +18,12 @@ import { getHost } from '../../../shared/utils'; styleUrls: ['spectra-object.component.css'], changeDetection: ChangeDetectionStrategy.OnPush }) +/** + * @class + * @classdesc Detail spectra object component. + * + * @implements OnInit + */ export class SpectraObjectComponent implements OnInit { @Input() datasetName: string; @Input() outputFamilyList: Family[]; @@ -36,6 +42,11 @@ export class SpectraObjectComponent implements OnInit { } } + /** + * Returns spectra file URL. + * + * @return string + */ getSpectra(): string { const spectraAttribute: Attribute = this.attributeList .filter(a => a.detail) @@ -43,12 +54,22 @@ export class SpectraObjectComponent implements OnInit { return getHost() + '/download-file/' + this.datasetName + '/' + this.object[spectraAttribute.label]; } + /** + * Returns detail rendered spectra graph attribute. + * + * @return Attribute + */ getAttributeSpectraGraph(): Attribute { return this.attributeList .filter(a => a.detail) .find(attribute => attribute.renderer_detail === 'spectra_graph'); } + /** + * Returns Z. + * + * @return number + */ getZ(): number { const attributeZ = this.attributeList .filter(a => a.detail) diff --git a/src/app/detail/containers/detail.component.ts b/src/app/detail/containers/detail.component.ts index 6a7df352c776540bef91b03156da9edb8e8709de..b196802440b04495eda709ec3cd93761b1a4cac9 100644 --- a/src/app/detail/containers/detail.component.ts +++ b/src/app/detail/containers/detail.component.ts @@ -19,6 +19,11 @@ import * as detailSelector from '../store/detail.selector'; import * as metamodelSelector from '../../metamodel/selectors'; import { Attribute, Category, Family } from '../../metamodel/model'; +/** + * Interface for store state. + * + * @interface StoreState + */ interface StoreState { detail: fromDetail.State; } @@ -27,6 +32,13 @@ interface StoreState { selector: 'app-detail-page', templateUrl: 'detail.component.html' }) +/** + * @class + * @classdesc Detail container. + * + * @implements OnInit + * @implements OnDestroy + */ export class DetailComponent implements OnInit, OnDestroy { public pristine: Observable<boolean>; public datasetName: Observable<string>; @@ -64,6 +76,13 @@ export class DetailComponent implements OnInit, OnDestroy { }); } + /** + * Returns the object type. + * + * @param {Attribute[]} attributeList - The attribute list. + * + * @return string + */ getObjectType(attributeList: Attribute[]): string { const spectrumAttribute: Attribute = attributeList .filter(a => a.detail) @@ -74,14 +93,25 @@ export class DetailComponent implements OnInit, OnDestroy { return 'default'; } - goBackToResult() { + /** + * Gets back to result page. + */ + goBackToResult(): void { this.location.back(); } - getSpectraCSV(spectraFile: string) { + /** + * Dispatches action to retrieve spectra file. + * + * @param {string} spectraFile - The spectra file name. + */ + getSpectraCSV(spectraFile: string): void { this.store.dispatch(new detailActions.RetrieveSpectraAction(spectraFile)); } + /** + * Resets detail information. + */ ngOnDestroy() { this.store.dispatch(new detailActions.DestroyDetailAction()); } diff --git a/src/app/detail/detail-routing.module.ts b/src/app/detail/detail-routing.module.ts index 34f687ee6ed47040a426d820a252951831b94f72..9d48dd53801e8f6538baae374c5a3ff842444f93 100644 --- a/src/app/detail/detail-routing.module.ts +++ b/src/app/detail/detail-routing.module.ts @@ -20,6 +20,10 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) +/** + * @class + * @classdesc Detail routing module. + */ export class DetailRoutingModule { } export const routedComponents = [ diff --git a/src/app/detail/detail.module.ts b/src/app/detail/detail.module.ts index fceb1d079237666b8f623e585655b57054985acd..89a8f1202e20f17dfda1864a1428f7ed9e6e3cb9 100644 --- a/src/app/detail/detail.module.ts +++ b/src/app/detail/detail.module.ts @@ -36,4 +36,8 @@ import { reducer } from './store/detail.reducer'; DetailService ] }) +/** + * @class + * @classdesc Detail module. + */ export class DetailModule { } diff --git a/src/app/detail/store/detail.action.ts b/src/app/detail/store/detail.action.ts index 389843cbee9518fa4dfd4bdf06d728683e582593..a228a63fd3388ac2acbb25db7fa5991a01d14c02 100644 --- a/src/app/detail/store/detail.action.ts +++ b/src/app/detail/store/detail.action.ts @@ -9,6 +9,7 @@ import { Action } from '@ngrx/store'; + export const INIT_DETAIL = '[Detail] Init Detail'; export const SET_SEARCH_IS_PRISTINE = '[Detail] Set Search Is Pristine'; export const SET_DATASET_NAME = '[Detail] Set Dataset Name'; @@ -20,60 +21,110 @@ export const RETRIEVE_SPECTRA_SUCCESS = '[Detail] Retrieve Spectra Success'; export const RETRIEVE_SPECTRA_FAIL = '[Detail] Retrieve Spectra Fail'; export const DESTROY_DETAIL = '[Detail] Destroy detail'; +/** + * @class + * @classdesc InitDetailAction action. + * @readonly + */ export class InitDetailAction implements Action { readonly type = INIT_DETAIL; constructor(public payload: {} = null) { } } +/** + * @class + * @classdesc SetDatasetNameAction action. + * @readonly + */ export class SetDatasetNameAction implements Action { readonly type = SET_DATASET_NAME; constructor(public payload: string) { } } +/** + * @class + * @classdesc SetSearchIsPristineAction action. + * @readonly + */ export class SetSearchIsPristineAction implements Action { readonly type = SET_SEARCH_IS_PRISTINE; constructor(public payload: boolean) { } } +/** + * @class + * @classdesc RetrieveObjectAction action. + * @readonly + */ export class RetrieveObjectAction implements Action { readonly type = RETRIEVE_OBJECT; constructor(public payload: { datasetName: string, idAttribute: number, id: string } = null) { } } +/** + * @class + * @classdesc RetrieveObjectSuccessAction action. + * @readonly + */ export class RetrieveObjectSuccessAction implements Action { readonly type = RETRIEVE_OBJECT_SUCCESS; constructor(public payload: any) { } } +/** + * @class + * @classdesc RetrieveObjectFailAction action. + * @readonly + */ export class RetrieveObjectFailAction implements Action { readonly type = RETRIEVE_OBJECT_FAIL; constructor(public payload: {} = null) { } } +/** + * @class + * @classdesc RetrieveSpectraAction action. + * @readonly + */ export class RetrieveSpectraAction implements Action { readonly type = RETRIEVE_SPECTRA; constructor(public payload: string) { } } +/** + * @class + * @classdesc RetrieveSpectraSuccessAction action. + * @readonly + */ export class RetrieveSpectraSuccessAction implements Action { readonly type = RETRIEVE_SPECTRA_SUCCESS; constructor(public payload: string) { } } +/** + * @class + * @classdesc RetrieveSpectraFailAction action. + * @readonly + */ export class RetrieveSpectraFailAction implements Action { readonly type = RETRIEVE_SPECTRA_FAIL; constructor(public payload: {} = null) { } } +/** + * @class + * @classdesc DestroyDetailAction action. + * @readonly + */ export class DestroyDetailAction implements Action { readonly type = DESTROY_DETAIL; diff --git a/src/app/detail/store/detail.effects.ts b/src/app/detail/store/detail.effects.ts index a996a8c6ee972d0912b36f8ae19641b94ff31ecc..20c4512dff81ac53f213fd7681dd34b813ceeaa1 100644 --- a/src/app/detail/store/detail.effects.ts +++ b/src/app/detail/store/detail.effects.ts @@ -25,6 +25,10 @@ import * as outputActions from '../../metamodel/action/output.action'; import * as fromSearch from '../../search/store/search.reducer'; import * as utils from '../../shared/utils'; +/** + * @class + * @classdesc Detail effects. + */ interface State { router: fromRouter.RouterReducerState<utils.RouterStateUrl>; metamodel: fromMetamodel.State; @@ -41,6 +45,9 @@ export class DetailEffects { private store$: Store<State> ) { } + /** + * Calls actions to initiate detail. + */ @Effect() initDetailAction$ = this.actions$.pipe( ofType(detailActions.INIT_DETAIL), @@ -62,6 +69,9 @@ export class DetailEffects { }) ); + /** + * Calls action to retrieve object details if attribute list is loaded. + */ @Effect() loadAttributeSuccessAction$ = this.actions$.pipe( ofType(attributeActions.LOAD_ATTRIBUTE_LIST_SUCCESS), @@ -75,29 +85,38 @@ export class DetailEffects { }) ); + /** + * Retrieves object details with given parameters. + */ @Effect() retrieveObjectAction$ = this.actions$.pipe( ofType(detailActions.RETRIEVE_OBJECT), withLatestFrom(this.store$), switchMap(([action, state]) => { - const datasetName = state.router.state.params.dname; + const dname = state.router.state.params.dname; const objectSelected = state.router.state.params.objectSelected; - const attributes = state.metamodel.attribute.entities[datasetName].attributeList; - const attributeCriterionId = attributes.find(a => a.search_flag === 'ID'); - const attributesOutputList = attributes.filter(a => a.detail).map(a => a.id); - return this.detailService.retrieveObject(datasetName, attributeCriterionId.id, objectSelected, attributesOutputList).pipe( + const attributes = state.metamodel.attribute.entities[dname].attributeList; + const criterionId = attributes.find(a => a.search_flag === 'ID'); + const outputList = attributes.filter(a => a.detail).map(a => a.id); + return this.detailService.retrieveObject(dname, criterionId.id, objectSelected, outputList).pipe( map((object: any[]) => new detailActions.RetrieveObjectSuccessAction(object[0])), catchError(() => of(new detailActions.RetrieveObjectFailAction())) ); }) ); + /** + * Displays retrieves object details error notification. + */ @Effect({ dispatch: false }) retrieveObjectFailAction$ = this.actions$.pipe( ofType(detailActions.RETRIEVE_OBJECT_FAIL), tap(_ => this.toastr.error('Loading Failed!', 'The object loading failed')) ); + /** + * Retrieves spectra. + */ @Effect() retrieveSpectraAction$ = this.actions$.pipe( ofType(detailActions.RETRIEVE_SPECTRA), @@ -109,6 +128,9 @@ export class DetailEffects { }) ); + /** + * Displays retrieves spectra error notification. + */ @Effect({ dispatch: false }) retrieveSpectraFailAction$ = this.actions$.pipe( ofType(detailActions.RETRIEVE_SPECTRA_FAIL), diff --git a/src/app/detail/store/detail.reducer.ts b/src/app/detail/store/detail.reducer.ts index b93fe27d1b0da0d7b693e2b8e62dd8064cfc173b..c7144333d68fcd9626eaf735ac691dabb9a22f6a 100644 --- a/src/app/detail/store/detail.reducer.ts +++ b/src/app/detail/store/detail.reducer.ts @@ -9,6 +9,11 @@ import * as actions from './detail.action'; +/** + * Interface for detail state. + * + * @interface State + */ export interface State { searchIsPristine: boolean datasetName: string; @@ -31,6 +36,14 @@ export const initialState: State = { spectraCSV: null }; +/** + * Reduces state. + * + * @param {State} state - The state. + * @param {actions} action - The action. + * + * @return State + */ export function reducer(state: State = initialState, action: actions.Actions): State { switch (action.type) { case actions.INIT_DETAIL: diff --git a/src/app/detail/store/detail.service.ts b/src/app/detail/store/detail.service.ts index b205bf2c0a93dc5d5769db85b29f35681b0caeec..dc867d1355d64b207e92d17be88453b6f883d8fb 100644 --- a/src/app/detail/store/detail.service.ts +++ b/src/app/detail/store/detail.service.ts @@ -10,21 +10,44 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + import { environment } from '../../../environments/environment'; @Injectable() +/** + * @class + * @classdesc Detail service. + */ export class DetailService { private API_PATH: string = environment.apiUrl + '/search/'; private SPECTRA_PATH: string = environment.spectraUrl; constructor(private http: HttpClient) { } - retrieveObject(datasetName: string, attributeCriterionId: number, objectSelected: string, attributesOutputList: number[]) { - const query = datasetName + '?c=' + attributeCriterionId + '::eq::' + objectSelected + '&a=' + attributesOutputList.join(';'); + /** + * Retrieves object details for the given parameters. + * + * @param {string} dname - The dataset name. + * @param {number} criterionId - The criterion ID. + * @param {string} objectSelected - The selected object ID. + * @param {number[]} outputList - The output list. + * + * @return Observable<any[]> + */ + retrieveObject(dname: string, criterionId: number, objectSelected: string, outputList: number[]): Observable<any[]> { + const query = dname + '?c=' + criterionId + '::eq::' + objectSelected + '&a=' + outputList.join(';'); return this.http.get<any[]>(this.API_PATH + query); } - retrieveSpectra(spectraFile: string) { + /** + * Retrieves object details for the given parameters. + * + * @param {string} spectraFile - The spectra file name. + * + * @return Observable<string> + */ + retrieveSpectra(spectraFile: string): Observable<string> { return this.http.get(this.SPECTRA_PATH + spectraFile, {responseType: 'text'}); } }