Skip to content
Snippets Groups Projects
Commit ef21a48e authored by Julian Matschinske's avatar Julian Matschinske
Browse files

Merge branch 'add-custom-proteins' into 'master'

Add custom proteins

See merge request covid-19/frontend!126
parents 4dc82cec b0b3f1ab
No related branches found
No related tags found
No related merge requests found
......@@ -103,7 +103,7 @@ export class AnalysisService {
this.selectListSubject.next({items: removedWrappers, selected: false});
}
public addAllHostProteins(nodes, proteins) {
public addVisibleHostProteins(nodes, proteins) {
const items: Wrapper[] = [];
const visibleIds = new Set<string>(nodes.getIds());
for (const protein of proteins) {
......@@ -117,7 +117,7 @@ export class AnalysisService {
this.selectListSubject.next({items, selected: true});
}
public addAllViralProteins(nodes, viralProteins) {
public addVisibleViralProteins(nodes, viralProteins) {
const items: Wrapper[] = [];
const visibleIds = new Set<string>(nodes.getIds());
for (const viralProtein of viralProteins) {
......@@ -131,6 +131,22 @@ export class AnalysisService {
this.selectListSubject.next({items, selected: true});
}
public removeAllHostProteins() {
const items: Wrapper[] = Array.from(this.selectedItems.values()).filter(p => p.type === 'host');
for (const wrapper of items) {
this.selectedItems.delete(wrapper.nodeId);
}
this.selectListSubject.next({items, selected: false});
}
public removeAllViralProteins() {
const items: Wrapper[] = Array.from(this.selectedItems.values()).filter(p => p.type === 'virus');
for (const wrapper of items) {
this.selectedItems.delete(wrapper.nodeId);
}
this.selectListSubject.next({items, selected: false});
}
resetSelection() {
this.selectListSubject.next({items: [], selected: null});
this.selectedItems.clear();
......
......@@ -19,6 +19,7 @@ import {AnalysisWindowComponent} from './components/analysis-window/analysis-win
import {TaskListComponent} from './components/task-list/task-list.component';
import {ToggleComponent} from './components/toggle/toggle.component';
import {InfoBoxComponent} from './components/info-box/info-box.component';
import {CustomProteinsComponent} from './components/custom-proteins/custom-proteins.component';
import {AnalysisService} from './analysis.service';
......@@ -36,6 +37,7 @@ import {AnalysisService} from './analysis.service';
TaskListComponent,
ToggleComponent,
InfoBoxComponent,
CustomProteinsComponent,
],
imports: [
BrowserModule,
......
<div class="modal" [class.is-active]="show">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">
<span class="icon"><i class="fa fa-dna"></i></span>
Add Custom Proteins
</p>
<button (click)="close()" class="delete" aria-label="close"></button>
</header>
<section class="modal-card-body">
<div class="notification is-success" *ngIf="itemsAdded.length > 0">
{{itemsAdded.length}} host proteins have been added to the selection.
</div>
<div class="notification is-warning" *ngIf="notFound.length > 0">
The following {{notFound.length}} Uniprot IDs could not be found and have been ignored:
<ul><li class="not-found" *ngFor="let nf of notFound">{{nf}}</li></ul>
</div>
<div class="field">
<label class="label" for="protein-list">List of Uniprot IDs</label>
<div class="control">
<textarea class="input" [ngModel]="textList" (ngModelChange)="changeTextList($event)" id="protein-list"></textarea>
</div>
</div>
<p *ngIf="proteins">
Proteins parsed: {{proteins.length}}
</p>
</section>
<footer class="modal-card-foot">
<button (click)="addProteins();" class="button is-success is-rounded has-tooltip"
data-tooltip="Add list of proteins to the selection."
[disabled]="proteins.length === 0">
<span class="icon">
<i class="fa fa-plus"></i>
</span>
<span>
Add
</span>
</button>
<button (click)="close()" class="button is-rounded has-tooltip" data-tooltip="Close the current window.">Close
</button>
</footer>
</div>
</div>
#protein-list {
height: 150px;
}
.not-found {
padding: 4px;
margin: 4px;
border-radius: 3px;
background-color: rgba(255, 255, 255, 0.33);
}
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {CustomProteinsComponent} from './custom-proteins.component';
import {HttpClientModule} from '@angular/common/http';
describe('CustomProteinsComponent', () => {
let component: CustomProteinsComponent;
let fixture: ComponentFixture<CustomProteinsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [CustomProteinsComponent],
imports: [HttpClientModule],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CustomProteinsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {environment} from '../../../environments/environment';
import {getWrapperFromProtein, Wrapper} from '../../interfaces';
import {AnalysisService} from '../../analysis.service';
@Component({
selector: 'app-custom-proteins',
templateUrl: './custom-proteins.component.html',
styleUrls: ['./custom-proteins.component.scss']
})
export class CustomProteinsComponent implements OnInit {
@Input()
public show = false;
@Output()
public showChange = new EventEmitter<boolean>();
public textList = '';
public proteins: Array<string> = [];
public notFound: Array<string> = [];
public itemsAdded: Array<Wrapper> = [];
constructor(private http: HttpClient, private analysis: AnalysisService) { }
ngOnInit(): void {
}
public close() {
this.show = false;
this.showChange.emit(this.show);
}
public async addProteins() {
this.notFound = [];
this.itemsAdded = [];
const proteins = this.proteins;
this.changeTextList('');
const result = await this.http.post<any>(`${environment.backend}query_proteins/`, proteins).toPromise();
this.notFound = result.notFound;
const details = result.details;
const items = [];
for (const detail of details) {
items.push(getWrapperFromProtein(detail));
}
this.itemsAdded = items;
this.analysis.addItems(items);
}
public changeTextList(textList) {
this.textList = textList;
if (!textList) {
this.proteins = [];
return;
}
const separators = ['\n', ',', ';', ' '];
let proteins;
for (const sep of separators) {
if (textList.indexOf(sep) === -1) {
continue;
}
proteins = textList.split(sep).map(ac => ac.trim()).filter(ac => !!ac);
break;
}
if (!proteins) {
proteins = [textList];
}
this.proteins = proteins;
}
}
......@@ -4,6 +4,9 @@
[dataset]="selectedDataset.backendId">
</app-launch-analysis>
<app-custom-proteins [(show)]="showCustomProteinsDialog">
</app-custom-proteins>
<div class="covex explorer">
<div class="covex left-window">
......@@ -387,7 +390,7 @@
</span>
</a>
</header>
<div *ngIf="collapseSelection">
<div *ngIf="collapseSelection" class="seed-selection">
<div class="card-content overflow">
<table class="table selection-table" *ngIf="analysis.getCount() > 0">
<thead>
......@@ -421,25 +424,56 @@
</i>
</div>
<footer class="card-footer">
<a (click)="analysis.addAllHostProteins(currentViewNodes, currentViewProteins)"
<a (click)="analysis.addVisibleHostProteins(currentViewNodes, currentViewProteins)"
class="card-footer-item has-text-success" data-tooltip="Add all visible host proteins.">
<span class="icon">
<i class="fa fa-plus"></i>
<i class="fa fa-eye"></i>
</span>
<span>
Host Proteins
</span>
</a>
<a (click)="analysis.addAllViralProteins(currentViewNodes, currentViewEffects)"
<a (click)="analysis.addVisibleViralProteins(currentViewNodes, currentViewEffects)"
class="card-footer-item has-text-success" data-tooltip="Add all visible viral proteins.">
<span class="icon">
<i class="fa fa-plus"></i>
<i class="fa fa-eye"></i>
</span>
<span>
Viral Proteins
</span>
</a>
</footer>
<footer class="card-footer">
<a (click)="analysis.removeAllHostProteins()"
class="card-footer-item has-text-danger" data-tooltip="Remove all host proteins.">
<span class="icon">
<i class="fa fa-minus"></i>
</span>
<span>
Host Proteins
</span>
</a>
<a (click)="analysis.removeAllViralProteins()"
class="card-footer-item has-text-danger" data-tooltip="Remove all viral proteins.">
<span class="icon">
<i class="fa fa-minus"></i>
</span>
<span>
Viral Proteins
</span>
</a>
</footer>
<footer class="card-footer">
<a (click)="showCustomProteinsDialog = true" class="card-footer-item has-text-primary"
data-tooltip="Add a custom list of proteins.">
<span class="icon">
<i class="fa fa-upload"></i>
</span>
<span>
Custom Proteins
</span>
</a>
</footer>
<footer class="card-footer">
<a (click)="analysis.resetSelection()" class="card-footer-item has-text-danger"
data-tooltip="Remove all entries of the selection.">
......
......@@ -41,3 +41,12 @@
padding: 15px;
font-weight: bold;
}
.seed-selection {
.card-footer {
font-size: 12px;
a {
padding: 3px;
}
}
}
......@@ -60,6 +60,8 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
public showAnalysisDialog = false;
public analysisDialogTarget: 'drug' | 'drug-target';
public showCustomProteinsDialog = false;
public selectedAnalysisToken: string | null = null;
public currentDataset = [];
......
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