diff --git a/src/app/components/shared/table/table.component.ts b/src/app/components/shared/table/table.component.ts index e8362383..08879edc 100644 --- a/src/app/components/shared/table/table.component.ts +++ b/src/app/components/shared/table/table.component.ts @@ -449,7 +449,15 @@ export class TableComponent implements OnInit, AfterViewChecked, OnChanges { } this.ontologyCols[column].missingValues = false; this.ontologyCols[column].values = {}; + + let isFirstRow = true this.data.rows.forEach((row) => { + // We don't want the template rows example values to be flagged up as missing associated ontologies. + if (this.templateRowPresent && isFirstRow) { + isFirstRow = false; + return; + } + if ( !this.isEmpty(row[column]) && (this.isEmpty(row[this.ontologyCols[column].ref]) || diff --git a/src/app/components/study/assays/assay-details/assay-details.component.html b/src/app/components/study/assays/assay-details/assay-details.component.html index e742838e..f31d5250 100644 --- a/src/app/components/study/assays/assay-details/assay-details.component.html +++ b/src/app/components/study/assays/assay-details/assay-details.component.html @@ -17,7 +17,7 @@ [fileTypes]="fileTypes" (rowsUpdated)="validateAssaySheet()" [tableData]="assay" - [templateRowPresent]="templateRow !== null" + [templateRowPresent]="rowTemplatePresent" validationsId="assays" > diff --git a/src/app/components/study/assays/assay-details/assay-details.component.ts b/src/app/components/study/assays/assay-details/assay-details.component.ts index 74eeff61..08e745af 100644 --- a/src/app/components/study/assays/assay-details/assay-details.component.ts +++ b/src/app/components/study/assays/assay-details/assay-details.component.ts @@ -5,6 +5,7 @@ import { Output, ViewChild, EventEmitter, + OnDestroy, } from "@angular/core"; import { select } from "@angular-redux/store"; import Swal from "sweetalert2"; @@ -12,14 +13,17 @@ import { EditorService } from "../../../../services/editor.service"; import { TableComponent } from "./../../../shared/table/table.component"; import { environment } from "src/environments/environment"; import { RowTemplateService } from "src/app/services/row-template.service"; +import { take } from "rxjs/operators"; @Component({ selector: "assay-details", templateUrl: "./assay-details.component.html", styleUrls: ["./assay-details.component.css"], }) -export class AssayDetailsComponent implements OnInit { +export class AssayDetailsComponent implements OnInit, OnDestroy { @Input("assayName") assayName: any; + @Input("rowTemplatePresent") rowTemplatePresent: boolean = false; + @Input("assay") inputassay: Record; @select((state) => state.study.assays) assays; @select((state) => state.study.samples) studySamples; @ViewChild(TableComponent) assayTable: TableComponent; @@ -46,6 +50,7 @@ export class AssayDetailsComponent implements OnInit { duplicateSampleNamesInAssay: any = []; templateRow = null; + templateRowInserted: boolean = false; constructor(private editorService: EditorService, private rowTemplateService: RowTemplateService) { if (!environment.isTesting) { @@ -70,17 +75,21 @@ export class AssayDetailsComponent implements OnInit { } setUpOnInitSubscriptions() { + console.log(this.inputassay); this.assays.subscribe((value) => { this.assay = value[this.assayName]; if (!this.isReadOnly) { - this.rowTemplateService.getTemplateRow(this.assayName).subscribe((tempObj) => { + /** + this.rowTemplateService.getTemplateRow(this.assayName).pipe( + take(1) + ).subscribe((tempObj) => { if (tempObj !== null) { this.templateRow = tempObj; this.insertTemplateRow(); } console.log(this.templateRow); - }); + });*/ } }); @@ -98,6 +107,16 @@ export class AssayDetailsComponent implements OnInit { } } + ngOnDestroy() { + /**if (this.assay) { + this.assay.data.rows.shift(); + for (let i = 0; i < this.assay.data.rows.length; i++) { + this.assay.data.rows[i].index -= 1; + } + }*/ + + } + onSamplesFilterKeydown(event, filterValue: string) { if (event.key === "Enter") { this.filteredSampleNames(filterValue); diff --git a/src/app/components/study/assays/assays.component.html b/src/app/components/study/assays/assays.component.html index 44acfe6f..d6586373 100644 --- a/src/app/components/study/assays/assays.component.html +++ b/src/app/components/study/assays/assays.component.html @@ -22,14 +22,21 @@ - - - +
+ + + + + - + +
+
 
@@ -45,4 +52,14 @@
 
 
+ +
 
+
 
+
+

Loading Assays

+ +
+
 
+
 
+
diff --git a/src/app/components/study/assays/assays.component.ts b/src/app/components/study/assays/assays.component.ts index 109c62e1..6e68a173 100644 --- a/src/app/components/study/assays/assays.component.ts +++ b/src/app/components/study/assays/assays.component.ts @@ -1,6 +1,29 @@ -import { Component, Output, EventEmitter } from "@angular/core"; +import { Component, Output, EventEmitter, platformCore } from "@angular/core"; import { select } from "@angular-redux/store"; import { environment } from "src/environments/environment"; +import { RowTemplateService } from "src/app/services/row-template.service"; +import { concatMap, map, take, toArray } from "rxjs/operators"; +import { Observable, Subject, combineLatest, forkJoin, from, of } from "rxjs"; + + +export class TemplateRowCollection { + nmr: Record; + lcms: Record; + gcms: Record; + dims: Record; + + constructor( + nmr: Record = {}, + lcms: Record = {}, + gcms: Record = {}, + dims: Record = {} + ) { + this.nmr = nmr; + this.lcms = lcms; + this.gcms = gcms; + this.dims = dims; + } +} @Component({ selector: "mtbls-assays", @@ -18,27 +41,37 @@ export class AssaysComponent { currentSubIndex = 0; assaysNames: any = []; - constructor() { + templateRows: TemplateRowCollection = new TemplateRowCollection(); + assaysPrepared: boolean = false; + rowTemplatesPrepared: boolean = false; + + + constructor(private rowTemplateService: RowTemplateService) { if (!environment.isTesting) { this.setUpSubscriptions(); } } setUpSubscriptions() { + const assaysLoadedSubject = new Subject(); + + // Regular subscription to assayFiles this.assayFiles.subscribe((assayfiles) => { this.studyAssayFiles = assayfiles; if (this.studyAssayFiles) { - // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < this.studyAssayFiles.length; i++) { this.assays.push({}); } } }); - - // eslint-disable-next-line @typescript-eslint/indent + this.studyAssays.subscribe((value) => { - if (this.studyAssayFiles) { - // @ts-ignore + //console.log(`studyAssays subscription value: ${JSON.stringify(value)}`) + console.log(`length of studyAssayFiles: ${this.studyAssayFiles}`); + console.log(`type of studyAssayFiles: ${typeof(this.studyAssayFiles)}`) + console.log(`keys value: ${Object.keys(value)}`) + if (this.studyAssayFiles && Object.keys(value).length === Object.keys(this.studyAssayFiles).length) { + console.log('we did it papa') let i = 0; this.studyAssayFiles.forEach((assayFileName) => { const assayName = assayFileName.filename.trim(); @@ -48,17 +81,130 @@ export class AssaysComponent { } i++; }); + assaysLoadedSubject.next('ready') } - // eslint-disable-next-line @typescript-eslint/indent }); - + this.readonly.subscribe((value) => { if (value !== null) { this.isReadOnly = value; + if (!this.isReadOnly) {} + } + }); + assaysLoadedSubject.subscribe((value) => console.log(value)); + + // Combined subscription to execute once both studyAssays and readonly have emitted + + combineLatest([assaysLoadedSubject, this.readonly]).pipe( + take(1) + ).subscribe(([studyAssaysValue, readonlyValue]) => { + if (!this.isReadOnly) { + console.log('we should be entering this !isReadonly block') + this.initializeTemplatePreparation(); + } else { + this.assaysPrepared = true; } }); } + // Method to get templates +getTemplates(): Observable { + const observables = this.assaysNames.map((assayName) => { + const attr = stripHyphensAndLowercase(this.rowTemplateService.getTemplateByAssayFilename(assayName)); + + // If template row already exists, return an observable that emits null + if (Object.keys(this.templateRows[attr]).length !== 0) { + return of(null); + } + + // Otherwise, make the HTTP call and map the response + return this.rowTemplateService.getTemplateRow(assayName).pipe( + take(1), + map((template) => { + if (template !== null) { + this.templateRows[attr] = template; + } + return this.templateRows; + }) + ); + }); + + // Use forkJoin to wait for all HTTP calls to complete + return forkJoin(observables); +} + +// Method to prepare template rows in assays +prepareTemplateRowsInAssays() { + //this.assaysPrepared = false; + console.log(`here are assayNames ${this.assaysNames}`) + this.assaysNames.forEach((assayName) => { + console.log('in assayNames callback') + const attr = stripHyphensAndLowercase(this.rowTemplateService.getTemplateByAssayFilename(assayName)); + if (Object.keys(this.templateRows[attr]).length !== 0) { + const index = this.assays.findIndex(assay => assay.name === assayName); + if (index !== -1) { + this.assays[index].data.rows.unshift(this.templateRows[attr]); + for (let i = 1; i < this.assays[index].data.rows.length; i++) { + this.assays[index].data.rows[i].index += 1; + } + } + + + } else { + console.warn(`Expected template row not found for ${attr}`); + } + this.assaysPrepared = true; + this.rowTemplatesPrepared = true; + }); +} + +// Method to initialize and ensure the correct order of operations +initializeTemplatePreparation() { + this.getTemplates().subscribe( + () => { + console.log('Templates retrieved.'); + this.prepareTemplateRowsInAssays(); + console.log('Templates prepared and rows are ready.'); + console.log(this.assays); + }, + (error) => { + console.error('Error during template preparation:', error); + } + ); +} + /** + getTemplates() { + this.assaysNames.forEach((assayName) => { + const attr = stripHyphensAndLowercase(this.rowTemplateService.getTemplateByAssayFilename(assayName)); + if (Object.keys(this.templateRows[attr]).length !== 0) return + + this.rowTemplateService.getTemplateRow(assayName).pipe( + take(1) + ).subscribe((template) => { + if (template !== null) { + this.templateRows[attr] = template; + } + }) + }); + console.log(this.templateRows); + } + + prepareTemplateRowsInAssays() { + this.assaysPrepared = false; + this.assaysNames.forEach((assayName) => { + const attr = stripHyphensAndLowercase(this.rowTemplateService.getTemplateByAssayFilename(assayName)); + if (Object.keys(this.templateRows[attr]).length !== 0) { + this.assays[assayName].data.rows.unshift(this.templateRows[attr]); + for (let i = 1; i < this.assays[assayName].data.rows.length; i++) { + this.assays[assayName].data.rows[i].index += 1; + } + } else { + console.warn(`Expected template row not found for ${attr}`); + } + this.assaysPrepared = true; + }) + }*/ + assayDeleted(name) { let i = 0; let assayIndex = -1; @@ -79,3 +225,7 @@ export class AssaysComponent { this.currentSubIndex = i; } } + +function stripHyphensAndLowercase(input: string): string { + return input.replace(/-/g, '').toLowerCase(); +} \ No newline at end of file diff --git a/src/app/services/row-template.service.ts b/src/app/services/row-template.service.ts index df1df705..9a868b9f 100644 --- a/src/app/services/row-template.service.ts +++ b/src/app/services/row-template.service.ts @@ -27,7 +27,7 @@ export class RowTemplateService { } getTemplateByAssayFilename(filename: string): AssayTemplateRow { - //if (filename.indexOf("NMR") > -1) return "NMR" + if (filename.indexOf("NMR") > -1) return "NMR" if (filename.indexOf("LC-MS") > -1) return "LC-MS" if (filename.indexOf("GC-MS") > -1) return "GC-MS" if (filename.indexOf("DI-MS") > -1) return "DI-MS"