diff --git a/src/app/analysis.service.ts b/src/app/analysis.service.ts index e87c9c2ee8cd3e3e69a71c59159bff6115925422..4acb83f3cd09d85c4a3ea5a0372cda2560382781 100644 --- a/src/app/analysis.service.ts +++ b/src/app/analysis.service.ts @@ -1,6 +1,8 @@ import {Injectable} from '@angular/core'; import {Protein} from './pages/protein-network'; import {Subject} from 'rxjs'; +import {HttpClient} from '@angular/common/http'; +import {environment} from '../environments/environment'; @Injectable({ providedIn: 'root' @@ -10,7 +12,17 @@ export class AnalysisService { private selectedProteins = new Map<string, Protein>(); private selectSubject = new Subject<{protein: Protein, selected: boolean}>(); - constructor() { + private token: string | null = null; + private stats: any; + private task: any; + + private intervalId: any; + + constructor(private http: HttpClient) { + this.token = localStorage.getItem('token'); + if (this.token) { + this.startWatching(); + } } addProtein(protein: Protein) { @@ -44,4 +56,44 @@ export class AnalysisService { }); } + getTask(): any { + return this.task; + } + + reset() { + this.token = null; + this.task = null; + this.stats = null; + if (this.intervalId) { + clearInterval(this.intervalId); + } + } + + getStats(): any { + return this.stats; + } + + async startAnalysis(algorithm, parameters) { + const resp = await this.http.post<any>(`${environment.backend}task/`, { + algorithm, + parameters, + }).toPromise(); + this.token = resp.token; + localStorage.setItem('token', this.token); + this.startWatching(); + } + + async startWatching() { + this.intervalId = setInterval(async () => { + const resp = await this.http.get<any>(`${environment.backend}task/?token=${this.token}`).toPromise().catch((e) => { + clearInterval(this.intervalId); + }); + this.task = resp.task; + this.stats = resp.stats; + if (this.task.done) { + clearInterval(this.intervalId); + } + }, 1000); + } + } diff --git a/src/app/components/protein-analysis/protein-analysis.component.html b/src/app/components/protein-analysis/protein-analysis.component.html index 166b412de19651f9150d2744910a5c7b4320d499..5786a67ec773aac7a442a43b6247c2b2707f3292 100644 --- a/src/app/components/protein-analysis/protein-analysis.component.html +++ b/src/app/components/protein-analysis/protein-analysis.component.html @@ -1,6 +1,6 @@ <div class="modal" [class.is-active]="show"> <div class="modal-background"></div> - <div class="modal-card"> + <div class="modal-card" *ngIf="!analysis.getTask()"> <header class="modal-card-head"> <p class="modal-card-title">Launch Protein Analysis</p> <button class="delete" aria-label="close" (click)="close()"></button> @@ -27,14 +27,70 @@ </table> </section> <footer class="modal-card-foot"> - <button class="button is-primary"> + <button class="button is-primary" [disabled]="true"> <span class="icon"><i class="fa fa-play"></i></span> <span>Multi Steiner</span> </button> - <button class="button is-primary"> + <button class="button is-primary" [disabled]="true"> <span class="icon"><i class="fa fa-play"></i></span> <span>Key Pathway Miner</span> </button> + <button class="button is-primary" (click)="startTask()"> + <span class="icon"><i class="fa fa-play"></i></span> + <span>Demo</span> + </button> </footer> </div> + <div class="modal-card" *ngIf="analysis.getTask()"> + <div *ngIf="!analysis.getTask().startedAt"> + <header class="modal-card-head"> + <p class="modal-card-title">Queued...</p> + <button class="delete" aria-label="close" (click)="close()"></button> + </header> + <section class="modal-card-body"> + <p> + Queue position: {{analysis.getStats().queuePosition}} + </p> + <p> + Queue length: {{analysis.getStats().queueLength}} + </p> + </section> + <footer class="modal-card-foot"> + <button class="button is-danger" (click)="analysis.reset()"> + <span class="icon"><i class="fa fa-stop"></i></span> + <span>Stop</span> + </button> + </footer> + </div> + <div *ngIf="analysis.getTask().startedAt && !analysis.getTask().done"> + <header class="modal-card-head"> + <p class="modal-card-title">Running...</p> + <button class="delete" aria-label="close" (click)="close()"></button> + </header> + <section class="modal-card-body"> + <progress class="progress is-primary" [value]="analysis.getTask().progress * 100" max="100">15%</progress> + </section> + <footer class="modal-card-foot"> + <button class="button is-danger" (click)="analysis.reset()"> + <span class="icon"><i class="fa fa-stop"></i></span> + <span>Stop</span> + </button> + </footer> + </div> + <div *ngIf="analysis.getTask().done"> + <header class="modal-card-head"> + <p class="modal-card-title">View Results</p> + <button class="delete" aria-label="close" (click)="close()"></button> + </header> + <section class="modal-card-body"> + <pre>{{analysis.getTask().result}}</pre> + </section> + <footer class="modal-card-foot"> + <button class="button is-danger" (click)="analysis.reset()"> + <span class="icon"><i class="fa fa-stop"></i></span> + <span>Discard</span> + </button> + </footer> + </div> + </div> </div> diff --git a/src/app/components/protein-analysis/protein-analysis.component.ts b/src/app/components/protein-analysis/protein-analysis.component.ts index 165b934e2fdffb3756ac67022d3074244e317dc8..358bf2ac7345e5772c801413025eaa746f29993e 100644 --- a/src/app/components/protein-analysis/protein-analysis.component.ts +++ b/src/app/components/protein-analysis/protein-analysis.component.ts @@ -25,4 +25,10 @@ export class ProteinAnalysisComponent implements OnInit { this.showChange.emit(this.show); } + public async startTask() { + await this.analysis.startAnalysis('dummy', { + proteins: this.analysis.getSelection().map((protein) => protein.proteinAc), + }); + } + } diff --git a/src/app/pages/explorer-page/explorer-page.component.html b/src/app/pages/explorer-page/explorer-page.component.html index aaaebed886c2e9d1eff538747c6a99a30b4202ae..e04d012906d40149442718b45785525fd1e09f61 100644 --- a/src/app/pages/explorer-page/explorer-page.component.html +++ b/src/app/pages/explorer-page/explorer-page.component.html @@ -133,12 +133,47 @@ </p> </header> <div class="card-content"> - <button (click)="showAnalysisDialog = true" class="button is-primary" [disabled]="analysis.getCount() === 0"> - <span class="icon"> - <i class="fa fa-list"></i> + <button (click)="showAnalysisDialog = true" + class="button" + [class.is-info]="!analysis.getTask()" + [class.is-warning]="analysis.getTask() && !analysis.getTask().startedAt" + [class.is-primary]="analysis.getTask() && analysis.getTask().startedAt && !analysis.getTask().done" + [class.is-success]="analysis.getTask() && analysis.getTask().done" + [disabled]="analysis.getCount() === 0 && !analysis.getTask()"> + <span *ngIf="!analysis.getTask()"> + <span class="icon"> + <i class="fa fa-list"></i> + </span> + <span> + Open Protein Selection + </span> + </span> + + <span *ngIf="analysis.getTask() && !analysis.getTask().startedAt"> + <span class="icon"> + <i class="fa fa-cog"></i> + </span> + <span> + Analysis queued... + </span> </span> - <span> - Open Protein Selection + + <span *ngIf="analysis.getTask() && !analysis.getTask().done && analysis.getTask().startedAt"> + <span class="icon"> + <i class="fa fa-cog fa-spin"></i> + </span> + <span> + Analysis running ({{analysis.getTask().progress | percent}}) + </span> + </span> + + <span *ngIf="analysis.getTask() && analysis.getTask().done"> + <span class="icon"> + <i class="fa fa-check"></i> + </span> + <span> + Analysis done + </span> </span> </button> </div> diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts index 9be11bd6f93489343f4810875a8c33144c6bd610..d98029875ef0905af385979773e28e717fd0d21e 100644 --- a/src/app/pages/explorer-page/explorer-page.component.ts +++ b/src/app/pages/explorer-page/explorer-page.component.ts @@ -405,6 +405,9 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { return false; } const protein = this.proteinData.getProtein(proteinAc); + if (!protein) { + return false; + } return this.analysis.inSelection(protein); } @@ -413,6 +416,9 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { return false; } const protein = this.proteinData.getProtein(proteinAc); + if (!protein) { + return false; + } this.analysis.addProtein(protein); } @@ -421,6 +427,9 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { return false; } const protein = this.proteinData.getProtein(proteinAc); + if (!protein) { + return false; + } this.analysis.removeProtein(protein); } diff --git a/src/app/pages/protein-network.ts b/src/app/pages/protein-network.ts index 4a1614122236f3bb638dc28835f2d6a7324dcbdc..efa08b44ddd7a7918784ce09f77e1298a784a2b3 100644 --- a/src/app/pages/protein-network.ts +++ b/src/app/pages/protein-network.ts @@ -51,11 +51,11 @@ export class ProteinNetwork { }); } - public getProtein(ac: string): Protein { + public getProtein(ac: string): Protein | undefined { return this.proteins.find((p) => p.proteinAc === ac); } - public getEffect(name: string, virus: string, dataset: string): Effect { + public getEffect(name: string, virus: string, dataset: string): Effect | undefined { return this.effects.find((eff) => eff.effectName === name && eff.virusName === virus && eff.datasetName === dataset); }