Skip to content
Snippets Groups Projects
Commit 8629ab3c authored by Julian Späth's avatar Julian Späth
Browse files

Merge branch 'extend-task-launch-and-result-view' into 'master'

Extend Analysis Launch and Result View

Closes #1

See merge request covid-19/frontend!51
parents 9774d737 08db12b6
No related branches found
No related tags found
No related merge requests found
......@@ -92,9 +92,10 @@ export class AnalysisService {
});
}
async startAnalysis(algorithm, parameters) {
async startAnalysis(algorithm, target: 'drug' | 'drug-target', parameters) {
const resp = await this.http.post<any>(`${environment.backend}task/`, {
algorithm,
target,
parameters,
}).toPromise();
this.tokens.push(resp.token);
......
<div *ngIf="token">
<div class="card analysis" *ngIf="task && task.info.done">
<div class="card analysis">
<header class="card-header">
<p class="card-header-title">
<span class="icon">
......@@ -13,9 +13,36 @@
</span>
</a>
</header>
<div class="card-content">
<div class="content">
<div class="tabs is-centered">
<ul>
<li [class.is-active]="tab === 'meta'"><a (click)="tab = 'meta'">Meta</a></li>
<li [class.is-active]="tab === 'network'"><a (click)="tab = 'network'">Network</a></li>
<li [class.is-active]="tab === 'table'"><a (click)="tab = 'table'">Table</a></li>
</ul>
</div>
<div class="content tab-content" *ngIf="task && task.info.done" [class.is-visible]="tab === 'meta'">
<div *ngIf="task">
<p>
Algorithm: {{task.info.algorithm}}
</p>
<div *ngIf="task.info.algorithm === 'trustrank'">
<table class="table is-narrow">
<tbody>
<tr>
<td>Damping Factor</td>
<td>{{task.info.parameters.dampingFactor}}</td>
</tr>
<tr>
<td>Result Size</td>
<td>{{task.info.parameters.resultSize}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="content tab-content" *ngIf="task && task.info.done" [class.is-visible]="tab === 'network'">
<div class="card-image">
<div class="network center" #network>
<button class="button is-loading center">Loading</button>
......@@ -71,79 +98,9 @@
</div>
</footer>
</div>
</div>
<div class="card analysis" *ngIf="task && !task.info.startedAt">
<header class="card-header">
<p class="card-header-title">
<span class="icon">
<i class="fas fa-cog" aria-hidden="true"></i>
</span>
Analysis Queued...
</p>
<a (click)="close()" class="card-header-icon" aria-label="close">
<span class="icon">
<i class="fas fa-times" aria-hidden="true"></i>
</span>
</a>
</header>
<div class="card-content">
<div class="content">
The analysis is queued
<!--TODO: Display queue information-->
</div>
</div>
<footer class="card-footer">
</footer>
</div>
<div class="card analysis" *ngIf="task && task.info.startedAt && !task.info.done">
<header class="card-header">
<p class="card-header-title">
<span class="icon">
<i class="fas fa-cog fa-spin" aria-hidden="true"></i>
</span>
Analysis in Progress...
</p>
<a (click)="close()" class="card-header-icon" aria-label="close">
<span class="icon">
<i class="fas fa-times" aria-hidden="true"></i>
</span>
</a>
</header>
<div class="card-content">
<div class="content">
The analysis is in progress
<!--TODO: Display analysis progress-->
</div>
</div>
<footer class="card-footer">
</footer>
</div>
<div class="card analysis" *ngIf="!task">
<header class="card-header">
<p class="card-header-title">
<span class="icon">
<i class="fas fa-question" aria-hidden="true"></i>
</span>
Analysis not found
</p>
<a (click)="close()" class="card-header-icon" aria-label="more options">
<span class="icon">
<i class="fas fa-times" aria-hidden="true"></i>
</span>
</a>
</header>
<div class="card-content">
<div class="content">
<span class="notification is-danger">
The analysis you were looking for is either gone or never existed.
</span>
</div>
<div class="content tab-content" *ngIf="task && task.info.done" [class.is-visible]="tab === 'table'">
TABLE
</div>
<footer class="card-footer">
</footer>
</div>
</div>
</div>
......@@ -3,3 +3,15 @@
height: 100%;
width: 100%;
}
div.network {
height: calc(100vh - 210px - 80px);
}
.tab-content {
visibility: hidden;
&.is-visible {
visibility: visible;
}
}
......@@ -12,7 +12,7 @@ import {
import {HttpClient} from '@angular/common/http';
import {environment} from '../../../environments/environment';
import {AnalysisService} from '../../analysis.service';
import {Protein, Task, NodeType, ViralProtein, QueryItem} from '../../interfaces';
import {Protein, Task, NodeType, ViralProtein} from '../../interfaces';
declare var vis: any;
......@@ -24,12 +24,6 @@ declare var vis: any;
export class AnalysisWindowComponent implements OnInit, OnChanges {
@Input() token: string | null = null;
@Input() selectedProteinName: string;
@Input() selectedProteinType: string;
@Input() selectedProteinAc: string;
@Input() selectedProteinItem: QueryItem;
@Input() selectedProteinVirus: string;
@Input() selectedProteinDataset: string;
@Output() tokenChange = new EventEmitter<string | null>();
@Output() showDetailsChange: EventEmitter<any> = new EventEmitter();
......@@ -43,6 +37,7 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
private nodeData: { nodes: any, edges: any } = {nodes: null, edges: null};
private drugNodes = [];
public showDrugs = false;
public tab = 'network';
constructor(private http: HttpClient, public analysis: AnalysisService) {
}
......@@ -79,14 +74,20 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
this.network.on('selectNode', (properties) => {
const selectedNodes = this.nodeData.nodes.get(properties.nodes);
if (selectedNodes.length > 0) {
let selectedProteinItem;
let selectedProteinName;
let selectedProteinType;
let selectedProteinAc;
let selectedProteinDataset;
let selectedProteinVirus;
if (selectedNodes[0].nodeType === 'host') {
const protein: Protein = {name: '', proteinAc: selectedNodes[0].id};
this.selectedProteinName = null;
this.selectedProteinDataset = null;
this.selectedProteinVirus = null;
this.selectedProteinItem = {name: selectedNodes[0].id, type: 'Host Protein', data: protein};
this.selectedProteinAc = protein.proteinAc;
this.selectedProteinType = 'Host Protein';
selectedProteinName = null;
selectedProteinDataset = null;
selectedProteinVirus = null;
selectedProteinItem = {name: selectedNodes[0].id, type: 'Host Protein', data: protein};
selectedProteinAc = protein.proteinAc;
selectedProteinType = 'Host Protein';
if (properties.event.srcEvent.ctrlKey) {
if (this.analysis.inSelection(protein.proteinAc)) {
this.analysis.removeItem(protein.proteinAc);
......@@ -96,33 +97,26 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
}
}
} else if (selectedNodes[0].nodeType === 'virus') {
const virus: ViralProtein = {effectName: selectedNodes[0].id, virusName: null, datasetName: null};
this.selectedProteinAc = null;
this.selectedProteinDataset = null;
this.selectedProteinVirus = null;
this.selectedProteinItem = {name: virus.effectName, type: 'Viral Protein', data: virus};
this.selectedProteinName = virus.effectName;
this.selectedProteinType = 'Viral Protein';
const virus: ViralProtein = {viralProteinId: null, effectName: selectedNodes[0].id, virusName: null, datasetName: null};
selectedProteinAc = null;
selectedProteinDataset = null;
selectedProteinVirus = null;
selectedProteinItem = {name: virus.effectName, type: 'Viral Protein', data: virus};
selectedProteinName = virus.effectName;
selectedProteinType = 'Viral Protein';
if (properties.event.srcEvent.ctrlKey) {
if (this.analysis.inSelection(virus.effectName)) {
this.analysis.removeItem(virus.effectName);
} else {
this.analysis.addItem(this.selectedProteinItem);
this.analysis.addItem(selectedProteinItem);
this.analysis.getCount();
}
}
}
this.showDetailsChange.emit([true, [this.selectedProteinItem, this.selectedProteinName,
this.selectedProteinType, this.selectedProteinAc, this.selectedProteinDataset, this.selectedProteinVirus]]);
this.showDetailsChange.emit([true, [selectedProteinItem, selectedProteinName, selectedProteinType, selectedProteinAc,
selectedProteinDataset, selectedProteinVirus]]);
} else {
this.selectedProteinItem = null;
this.selectedProteinName = null;
this.selectedProteinType = null;
this.selectedProteinAc = null;
this.selectedProteinDataset = null;
this.selectedProteinVirus = null;
this.showDetailsChange.emit([false, [this.selectedProteinItem, this.selectedProteinName,
this.selectedProteinType, this.selectedProteinAc, this.selectedProteinDataset, this.selectedProteinVirus]]);
this.showDetailsChange.emit([false, [null, null, null, null, null, null]]);
}
});
......
......@@ -2,35 +2,32 @@
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Launch Analysis</p>
<p class="modal-card-title" *ngIf="target === 'drug'">
<span class="icon"><i class="fa fa-capsules"></i></span>
Find Drugs
</p>
<p class="modal-card-title" *ngIf="target === 'drug-target'">
<span class="icon"><i class="fa fa-crosshairs"></i></span>
Find Drug Targets
</p>
<button (click)="close()" class="delete" aria-label="close"></button>
</header>
<section class="modal-card-body">
<div class="tabs is-toggle is-small is-fullwidth is-rounded">
<ul>
<li [class.is-active]="algorithm === 'dummy'">
<a (click)="algorithm = 'dummy'" class="is-boxed is-medium">Dummy</a>
</li>
<li [class.is-active]="algorithm === 'trustrank'">
<a (click)="algorithm = 'trustrank'" class="is-boxed is-medium">Trustrank</a>
</li>
<li [class.is-active]="algorithm === 'keypathwayminer'">
<a (click)="algorithm = 'keypathwayminer'" class="is-boxed is-medium">KeyPathwayMiner</a>
</li>
<li [class.is-active]="algorithm === 'multisteiner'">
<a (click)="algorithm = 'multisteiner'" class="is-boxed is-medium">Multi-Steiner</a>
<li [class.is-active]="algorithm === algo.slug" *ngFor="let algo of algorithms">
<a (click)="algorithm = algo.slug" class="is-boxed is-medium">{{algo.name}}</a>
</li>
</ul>
</div>
<div *ngIf="algorithm==='trustrank'">
<div class="field">
<div class="field" *ngIf="target === 'drug-target'">
<label class="label" for="trustrank-strain">Strain</label>
<div class="control">
<div class="select">
<select id="trustrank-strain" [(ngModel)]="trustrankStrain">
<option [ngValue]="'SARS_CoV2'">SARS Coronavirus 2</option>
<option [ngValue]="'drugs'">Drugs</option>
</select>
</div>
</div>
......
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges} from '@angular/core';
import {AnalysisService} from '../../analysis.service';
interface Algorithm {
slug: string;
name: string;
}
const DUMMY: Algorithm = {slug: 'dummy', name: 'Dummy'};
const TRUSTRANK: Algorithm = {slug: 'trustrank', name: 'Trust-Rank'};
const KEYPATHWAYMINER: Algorithm = {slug: 'keypathwayminer', name: 'KeyPathwayMiner'};
const MULTISTEINER: Algorithm = {slug: 'multisteiner', name: 'Multi-Steiner'};
@Component({
selector: 'app-launch-analysis',
templateUrl: './launch-analysis.component.html',
styleUrls: ['./launch-analysis.component.scss']
})
export class LaunchAnalysisComponent implements OnInit {
export class LaunchAnalysisComponent implements OnInit, OnChanges {
@Input()
public show = false;
@Input()
public target: 'drug' | 'drug-target';
@Output()
public showChange = new EventEmitter<boolean>();
public algorithm: 'dummy' | 'trustrank' | 'keypathwayminer' | 'multisteiner';
public algorithms: Array<Algorithm> = [];
// Trustrank Parameters
public trustrankStrain = 'SARS_CoV2';
public trustrankDampingFactor = 0.85;
......@@ -36,6 +50,16 @@ export class LaunchAnalysisComponent implements OnInit {
ngOnInit(): void {
}
ngOnChanges(changes: SimpleChanges): void {
if (this.target === 'drug-target') {
this.algorithms = [TRUSTRANK, MULTISTEINER, KEYPATHWAYMINER, DUMMY];
this.trustrankStrain = 'SARS_CoV2';
} else if (this.target === 'drug') {
this.algorithms = [TRUSTRANK, DUMMY];
this.trustrankStrain = 'drugs';
}
}
public close() {
this.show = false;
this.showChange.emit(this.show);
......@@ -60,10 +84,9 @@ export class LaunchAnalysisComponent implements OnInit {
} else if (this.algorithm === 'multisteiner') {
parameters.strain = this.multisteinerStrain;
parameters.num_trees = this.multisteinerNumTrees;
}
await this.analysis.startAnalysis(this.algorithm, parameters);
await this.analysis.startAnalysis(this.algorithm, this.target, parameters);
}
}
......@@ -3,7 +3,7 @@
<a *ngFor="let task of analysis.tasks" class="list-item" [class.is-active]="task.token === token">
<div *ngIf="!task.info.startedAt" (click)="open(task.token)">
<p>
<span class="is-capitalized">{{task.info.algorithm}}</span>
<span class="is-capitalized"><i class="fa" [class.fa-capsules]="task.info.target === 'drug'" [class.fa-crosshairs]="task.info.target === 'drug-target'"></i> {{task.info.algorithm}}</span>
<span class="icon is-pulled-right"><i class="fas fa-pause" aria-hidden="true"></i></span>
</p>
<p>
......@@ -12,7 +12,7 @@
</div>
<div *ngIf="!task.info.done && !task.info.failed && task.info.startedAt" (click)="open(task.token)">
<p>
<span class="is-capitalized">{{task.info.algorithm}}</span>
<span class="is-capitalized"><i class="fa" [class.fa-capsules]="task.info.target === 'drug'" [class.fa-crosshairs]="task.info.target === 'drug-target'"></i> {{task.info.algorithm}}</span>
<span class="icon is-pulled-right"><i class="fas fa-spinner fa-spin" aria-hidden="true"></i></span>
</p>
<p>
......@@ -23,7 +23,7 @@
</div>
<div *ngIf="task.info.done" (click)="open(task.token)">
<p>
<span class="is-capitalized">{{task.info.algorithm}}</span>
<span class="is-capitalized"><i class="fa" [class.fa-capsules]="task.info.target === 'drug'" [class.fa-crosshairs]="task.info.target === 'drug-target'"></i> {{task.info.algorithm}}</span>
<span class="icon is-pulled-right"><i class="fas fa-check" aria-hidden="true"></i></span>
</p>
<p>
......@@ -32,7 +32,7 @@
</div>
<div *ngIf="task.info.failed && task.info.finishedAt == null">
<p>
<span class="is-capitalized">{{task.info.algorithm}}</span>
<span class="is-capitalized"><i class="fa" [class.fa-capsules]="task.info.target === 'drug'" [class.fa-crosshairs]="task.info.target === 'drug-target'"></i> {{task.info.algorithm}}</span>
<span class="icon is-pulled-right"><i class="fas fa-exclamation-triangle" aria-hidden="true"></i></span>
</p>
<p class="has-text-danger">
......
......@@ -9,6 +9,7 @@ export interface Protein {
}
export interface ViralProtein {
viralProteinId: string;
effectName: string;
virusName: string;
datasetName: string;
......@@ -27,6 +28,7 @@ export interface ProteinViralInteraction {
export interface Task {
token: string;
info: {
target: 'drug' | 'drug-target',
algorithm: 'trustrank' | 'multisteiner' | 'keypathwayminer';
parameters?: { [key: string]: any };
......
<app-launch-analysis [(show)]="showAnalysisDialog"></app-launch-analysis>
<app-launch-analysis [(show)]="showAnalysisDialog" [target]="analysisDialogTarget"></app-launch-analysis>
<div class="covex explorer">
......@@ -260,16 +260,34 @@
</header>
<div *ngIf="collabsAnalysis">
<div class="card-content">
<button (click)="showAnalysisDialog = true"
class="button is-primary is-fullwidth is-rounded"
[disabled]="analysis.getCount() === 0">
<span class="icon">
<i class="fa fa-rocket"></i>
</span>
<span>
Launch Analysis
</span>
</button>
<div class="field">
<div class="control">
<button (click)="analysisDialogTarget = 'drug-target'; showAnalysisDialog = true;"
class="button is-primary is-fullwidth is-rounded"
[disabled]="analysis.getCount() === 0">
<span class="icon">
<i class="fa fa-crosshairs"></i>
</span>
<span>
Find Drug Targets
</span>
</button>
</div>
</div>
<div class="field">
<div class="control">
<button (click)="analysisDialogTarget = 'drug'; showAnalysisDialog = true;"
class="button is-primary is-fullwidth is-rounded"
[disabled]="analysis.getCount() === 0">
<span class="icon">
<i class="fa fa-capsules"></i>
</span>
<span>
Find Drugs
</span>
</button>
</div>
</div>
</div>
</div>
</div>
......
......@@ -55,6 +55,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
public queryItems: QueryItem[] = [];
public showAnalysisDialog = false;
public analysisDialogTarget: 'drug' | 'drug-target';
public selectedAnalysisToken: string | null = null;
......
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