diff --git a/src/app/components/analysis-panel/analysis-panel.component.html b/src/app/components/analysis-panel/analysis-panel.component.html index 8677a27fe0b01fb4a91b1143607ec36d9846bdc5..95b6ac1be0ec83bd173f16b2b1da72f53ff568f4 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.html +++ b/src/app/components/analysis-panel/analysis-panel.component.html @@ -13,7 +13,7 @@ <div class="field has-addons"> <p class="control" *ngIf="!fullscreen"> <button - (click)="analysis.removeTask(token); close()" + (click)="analysis.removeAnalysis(token, tokenType); close()" class="button is-rounded is-small is-outlined highlight-danger has-text-danger" aria-label="delete" pTooltip="Delete analysis" @@ -109,13 +109,13 @@ > <div class="tabs is-centered tabs-header"> <ul> - <li [class.is-active]="tab === 'table'"> + <li [class.is-active]="tab === 'table'" *ngIf="tokenType!=='view'"> <a (click)="tab = 'table'">Table</a> </li> <li [class.is-active]="tab === 'network'"> <a (click)="tab = 'network'">Network</a> </li> - <li [class.is-active]="tab === 'meta'"> + <li [class.is-active]="tab === 'meta'" *ngIf="tokenType!=='view'"> <a (click)="tab = 'meta'">Parameters</a> </li> </ul> @@ -145,7 +145,8 @@ </div> <div class="columns m-1"> <div class="column"> - <table class="table parameter-table" *ngIf="['quick', 'super', 'connect', 'connectSelected'].includes(task.info.algorithm)"> + <table class="table parameter-table" + *ngIf="['quick', 'super', 'connect', 'connectSelected'].includes(task.info.algorithm)"> <tbody> <tr *ngIf="result && result.geneInteractionDataset !== undefined" @@ -169,7 +170,8 @@ </tr> </tbody> </table> - <table class="table parameter-table" *ngIf="!['quick', 'super', 'connect', 'connectSelected'].includes(task.info.algorithm)"> + <table class="table parameter-table" + *ngIf="!['quick', 'super', 'connect', 'connectSelected'].includes(task.info.algorithm)"> <tbody> <tr *ngIf="result && result.geneInteractionDataset !== undefined" @@ -191,95 +193,95 @@ {{ result.drugInteractionDataset.version }}] </td> </tr> - <tr *ngIf="task.info.parameters.resultSize !== undefined"> - <td>Result Size</td> - <td>{{ task.info.parameters.resultSize }}</td> - </tr> - <tr *ngIf="task.info.parameters.k !== undefined"> - <td>K</td> - <td>{{ task.info.parameters.k }}</td> - </tr> - <tr *ngIf="task.info.parameters.numTrees !== undefined"> - <td>Number of trees</td> - <td>{{ task.info.parameters.numTrees }}</td> - </tr> - <tr *ngIf="task.info.parameters.tolerance !== undefined"> - <td>Tolerance</td> - <td>{{ task.info.parameters.tolerance }}</td> - </tr> - <tr *ngIf="task.info.parameters.dampingFactor !== undefined"> - <td>Damping Factor</td> - <td>{{ task.info.parameters.dampingFactor }}</td> - </tr> - <tr *ngIf="task.info.parameters.maxDeg !== undefined"> - <td>Maximum Degree</td> - <td>{{ task.info.parameters.maxDeg }}</td> - </tr> - <tr *ngIf="task.info.parameters.hubPenalty !== undefined"> - <td>Hub Penality</td> - <td>{{ task.info.parameters.hubPenalty }}</td> - </tr> - <tr - *ngIf=" + <tr *ngIf="task.info.parameters.resultSize !== undefined"> + <td>Result Size</td> + <td>{{ task.info.parameters.resultSize }}</td> + </tr> + <tr *ngIf="task.info.parameters.k !== undefined"> + <td>K</td> + <td>{{ task.info.parameters.k }}</td> + </tr> + <tr *ngIf="task.info.parameters.numTrees !== undefined"> + <td>Number of trees</td> + <td>{{ task.info.parameters.numTrees }}</td> + </tr> + <tr *ngIf="task.info.parameters.tolerance !== undefined"> + <td>Tolerance</td> + <td>{{ task.info.parameters.tolerance }}</td> + </tr> + <tr *ngIf="task.info.parameters.dampingFactor !== undefined"> + <td>Damping Factor</td> + <td>{{ task.info.parameters.dampingFactor }}</td> + </tr> + <tr *ngIf="task.info.parameters.maxDeg !== undefined"> + <td>Maximum Degree</td> + <td>{{ task.info.parameters.maxDeg }}</td> + </tr> + <tr *ngIf="task.info.parameters.hubPenalty !== undefined"> + <td>Hub Penality</td> + <td>{{ task.info.parameters.hubPenalty }}</td> + </tr> + <tr + *ngIf=" task.info.parameters.includeIndirectDrugs !== undefined && task.info.target === 'drug' " - > - <td>Include indirect drugs</td> - <td> - <app-fa-solid-icon - *ngIf="task.info.parameters.includeIndirectDrugs" - icon="check" - title="indirect drugs included" - classString="has-text-success" - ></app-fa-solid-icon> - <app-fa-solid-icon - *ngIf="!task.info.parameters.includeIndirectDrugs" - icon="times" - classString="has-text-danger" - title="indirect drugs excluded" - ></app-fa-solid-icon> - </td> - </tr> - <tr - *ngIf=" + > + <td>Include indirect drugs</td> + <td> + <app-fa-solid-icon + *ngIf="task.info.parameters.includeIndirectDrugs" + icon="check" + title="indirect drugs included" + classString="has-text-success" + ></app-fa-solid-icon> + <app-fa-solid-icon + *ngIf="!task.info.parameters.includeIndirectDrugs" + icon="times" + classString="has-text-danger" + title="indirect drugs excluded" + ></app-fa-solid-icon> + </td> + </tr> + <tr + *ngIf=" task.info.parameters.includeNonApprovedDrugs !== undefined && task.info.target === 'drug' " - > - <td>Include non-approved drugs</td> - <td> - <app-fa-solid-icon - *ngIf="task.info.parameters.includeNonApprovedDrugs" - icon="check" - title="non-approved drugs included" - classString="has-text-success" - ></app-fa-solid-icon> - <app-fa-solid-icon - *ngIf="!task.info.parameters.includeNonApprovedDrugs" - icon="times" - classString="has-text-danger" - title="non-approved drugs excluded" - ></app-fa-solid-icon> - </td> - </tr> - <tr *ngIf="task.info.parameters.customEdges !== undefined"> - <td>Include all displayed edges</td> - <td> - <app-fa-solid-icon - *ngIf="task.info.parameters.customEdges" - icon="check" - title="custom edges drugs included" - classString="has-text-success" - ></app-fa-solid-icon> - <app-fa-solid-icon - *ngIf="!task.info.parameters.customEdges" - icon="times" - classString="has-text-danger" - title="custom edges drugs excluded" - ></app-fa-solid-icon> - </td> - </tr> + > + <td>Include non-approved drugs</td> + <td> + <app-fa-solid-icon + *ngIf="task.info.parameters.includeNonApprovedDrugs" + icon="check" + title="non-approved drugs included" + classString="has-text-success" + ></app-fa-solid-icon> + <app-fa-solid-icon + *ngIf="!task.info.parameters.includeNonApprovedDrugs" + icon="times" + classString="has-text-danger" + title="non-approved drugs excluded" + ></app-fa-solid-icon> + </td> + </tr> + <tr *ngIf="task.info.parameters.customEdges !== undefined"> + <td>Include all displayed edges</td> + <td> + <app-fa-solid-icon + *ngIf="task.info.parameters.customEdges" + icon="check" + title="custom edges drugs included" + classString="has-text-success" + ></app-fa-solid-icon> + <app-fa-solid-icon + *ngIf="!task.info.parameters.customEdges" + icon="times" + classString="has-text-danger" + title="custom edges drugs excluded" + ></app-fa-solid-icon> + </td> + </tr> </tbody> </table> </div> diff --git a/src/app/components/analysis-panel/analysis-panel.component.ts b/src/app/components/analysis-panel/analysis-panel.component.ts index 3dd071722b7b14fd45759b9bfd2b3dd825bf182e..0cccfaf786579542cfd546b5789737bc74a4247c 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.ts +++ b/src/app/components/analysis-panel/analysis-panel.component.ts @@ -26,7 +26,7 @@ import { } from '../../interfaces'; import {NetworkSettings} from '../../network-settings'; import {NetexControllerService} from 'src/app/services/netex-controller/netex-controller.service'; -import {mapCustomEdge} from 'src/app/main-network'; +import {mapCustomEdge, mapNetexEdge, ProteinNetwork} from 'src/app/main-network'; import {DrugstoneConfigService} from 'src/app/services/drugstone-config/drugstone-config.service'; import {NetworkHandlerService} from 'src/app/services/network-handler/network-handler.service'; import {LegendService} from 'src/app/services/legend-service/legend-service.service'; @@ -73,7 +73,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit public nodeData: { nodes: any, edges: any } = {nodes: null, edges: null}; // private drugNodes: any[] = []; // private drugEdges: any[] = []; - public tab: 'meta' | 'network' | 'table' = 'table'; + public tab: 'meta' | 'network' | 'table' = 'network'; // public adjacentDrugs = false; // public adjacentDrugList: Node[] = []; @@ -145,263 +145,474 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit } } - private async refresh() { - if (this.token) { - if (this.tokenType === 'view') { - this.loadingScreen.stateUpdate(true); - this.task = await this.getView(this.token); - console.log(this.task) - this.analysis.switchSelection(this.token); - this.loadingScreen.stateUpdate(false); - } else { - this.loadingScreen.stateUpdate(true); - this.task = await this.getTask(this.token); - this.analysis.switchSelection(this.token); - - if (this.task.info.algorithm === 'degree') { - this.tableDrugScoreTooltip = - 'Normalized number of direct interactions of the drug with the seeds. ' + - 'The higher the score, the more relevant the drug.'; - this.tableProteinScoreTooltip = - 'Normalized number of direct interactions of the protein with the seeds. ' + - 'The higher the score, the more relevant the protein.'; - } else if (this.task.info.algorithm === 'closeness' || this.task.info.algorithm === 'quick' || this.task.info.algorithm === 'super') { - this.tableDrugScoreTooltip = - 'Normalized inverse mean distance of the drug to the seeds. ' + - 'The higher the score, the more relevant the drug.'; - this.tableProteinScoreTooltip = - 'Normalized inverse mean distance of the protein to the seeds. ' + - 'The higher the score, the more relevant the protein.'; - } else if (this.task.info.algorithm === 'trustrank') { - this.tableDrugScoreTooltip = - 'Amount of ‘trust’ on the drug at termination of the algorithm. ' + - 'The higher the score, the more relevant the drug.'; - this.tableProteinScoreTooltip = - 'Amount of ‘trust’ on the protein at termination of the algorithm. ' + - 'The higher the score, the more relevant the protein.'; - } else if (this.task.info.algorithm === 'proximity') { - this.tableDrugScoreTooltip = - 'Empirical z-score of mean minimum distance between the drug’s targets and the seeds. ' + - 'The lower the score, the more relevant the drug.'; - this.tableProteinScoreTooltip = - 'Empirical z-score of mean minimum distance between the drug’s targets and the seeds. ' + - 'The lower the score, the more relevant the drug.'; + private async refreshView() { + this.loading = true; + this.loadingScreen.stateUpdate(true); + this.getView(this.token).then(async view => { + this.task = view; + this.result = view; + this.drugstoneConfig.set_analysisConfig(view.config); + this.analysis.switchSelection(this.token); + this.loadingScreen.stateUpdate(false); + + + // Reset + this.nodeData = {nodes: null, edges: null}; + // this.networkHandler.activeNetwork.networkEl.nativeElement.innerHTML = ''; + // this.networkHandler.activeNetwork.networkInternal = null; + // Create+ + return new Promise<any>(async (resolve, reject) => { + const nodes = view.network.nodes; + let edges = view.network.edges; + + if (this.drugstoneConfig.config.autofillEdges && nodes.length) { + const node_map = {}; + nodes.filter(n => n.drugstoneType === 'protein').forEach(node => { + if (typeof node.drugstoneId === 'string') { + if (node_map[node.drugstoneId]) { + node_map[node.drugstoneId].push(node.id); + } else { + node_map[node.drugstoneId] = [node.id]; + } + } else { + node.drugstoneId.forEach(n => { + if (node_map[n]) { + node_map[n].push(node.id); + } else { + node_map[n] = [node.id]; + } + }); + } + }); + const netexEdges = await this.netex.fetchEdges(nodes, this.drugstoneConfig.config.interactionProteinProtein, this.drugstoneConfig.config.licensedDatasets); + edges.push(...netexEdges.map(netexEdge => mapNetexEdge(netexEdge, this.drugstoneConfig.currentConfig(), node_map)).flatMap(e => e)); } - if (this.task && this.task.info && this.task.info.done) { + const edge_map = {}; + + edges = edges.filter(edge => { + if (edge_map[edge.to] && edge_map[edge.to].indexOf(edge.from) !== -1) { + return false; + } + if (edge_map[edge.from] && edge_map[edge.from].indexOf(edge.to) !== -1) { + return false; + } + if (!edge_map[edge.from]) { + edge_map[edge.from] = [edge.to]; + } else { + edge_map[edge.from].push(edge.to); + } + return true; + }); + + // @ts-ignore + if (!this.drugstoneConfig.selfReferences) { + edges = edges.filter(el => el.from !== el.to); + } - this.loading = true; - this.netex.getTaskResult(this.token).then(async result => { - this.drugstoneConfig.set_analysisConfig(result.parameters.config); - this.result = result; - if (this.result.parameters.target === 'drug') { - this.legendService.add_to_context('drug'); + this.networkHandler.activeNetwork.inputNetwork = {nodes: nodes, edges: edges}; + this.nodeData.nodes = new vis.DataSet(nodes); + this.nodeData.edges = new vis.DataSet(edges); + const container = this.networkHandler.activeNetwork.networkEl.nativeElement; + const isBig = nodes.length > 100 || edges.length > 100; + const options = NetworkSettings.getOptions(isBig ? 'analysis-big' : 'analysis', this.drugstoneConfig.currentConfig()); + // @ts-ignore + options.groups = this.drugstoneConfig.currentConfig().nodeGroups; + // @ts-ignore + for (const g of Object.values(options.groups)) { + // @ts-ignore + delete g.renderer; + } + if (this.drugstoneConfig.config.physicsOn) { + this.drugstoneConfig.config.physicsOn = !isBig; + } + this.networkHandler.activeNetwork.networkInternal = new vis.Network(container, this.nodeData, options); + + if (isBig) { + resolve(nodes); + } + this.networkHandler.activeNetwork.networkInternal.once('stabilizationIterationsDone', async () => { + if (!this.drugstoneConfig.config.physicsOn || this.networkHandler.activeNetwork.isBig()) { + this.networkHandler.activeNetwork.updatePhysicsEnabled(false); + } + this.networkHandler.updateAdjacentNodes(this.networkHandler.activeNetwork.isBig()).then(() => { + resolve(nodes); + }); + }); + }).then(() => { + this.networkHandler.activeNetwork.networkInternal.on('deselectNode', (properties) => { + this.showDetailsChange.emit(null); + }); + + this.networkHandler.activeNetwork.networkInternal.on('doubleClick', (properties) => { + const nodeIds: Array<string> = properties.nodes; + if (nodeIds.length > 0) { + const nodeId = nodeIds[0]; + const node = this.nodeData.nodes.get(nodeId); + if (node.drugstoneId === undefined || node.nodeType === 'drug' || node.drugstoneType !== 'protein') { + this.analysis.unmappedNodeToast(); + return; + } + const wrapper = getWrapperFromNode(node); + if (this.analysis.inSelection(wrapper)) { + this.analysis.removeItems([wrapper]); + this.analysis.getCount(); } else { - this.legendService.add_to_context('drugTarget'); + this.analysis.addItems([wrapper]); + this.analysis.getCount(); } - const nodeAttributes = this.result.nodeAttributes || {}; - - this.networkHandler.activeNetwork.seedMap = nodeAttributes.isSeed || {}; - - // Reset - this.nodeData = {nodes: null, edges: null}; - this.networkHandler.activeNetwork.networkEl.nativeElement.innerHTML = ''; - this.networkHandler.activeNetwork.networkInternal = null; - // Create - await this.createNetwork(this.result).then(nw => { - return new Promise<any>((resolve, reject) => { - - const nodes = nw.nodes; - const edges = nw.edges; - this.networkHandler.activeNetwork.inputNetwork = {nodes: nodes, edges: edges}; - this.nodeData.nodes = new vis.DataSet(nodes); - this.nodeData.edges = new vis.DataSet(edges); - const container = this.networkHandler.activeNetwork.networkEl.nativeElement; - const isBig = nodes.length > 100 || edges.length > 100; - const options = NetworkSettings.getOptions(isBig ? 'analysis-big' : 'analysis', this.drugstoneConfig.currentConfig()); - // @ts-ignore - options.groups = this.drugstoneConfig.currentConfig().nodeGroups; - // @ts-ignore - for (const g of Object.values(options.groups)) { - // @ts-ignore - delete g.renderer; - } - if (this.drugstoneConfig.config.physicsOn) { - this.drugstoneConfig.config.physicsOn = !isBig; - } - this.networkHandler.activeNetwork.networkInternal = new vis.Network(container, this.nodeData, options); + } + }); + + this.networkHandler.activeNetwork.networkInternal.on('click', (properties) => { + if (properties.nodes.length === 0 && properties.edges.length === 1) { + // clicked on one edge + const edgeId = properties.edges[0]; + this.networkHandler.activeNetwork.openEdgeSummary(edgeId); + } else { + this.networkHandler.activeNetwork.activeEdge = null; + const selectedNodes = this.nodeData.nodes.get(properties.nodes); + if (selectedNodes.length > 0) { + this.showDetailsChange.emit(getWrapperFromNode(selectedNodes[0])); + } else { + this.showDetailsChange.emit(null); + } + } + }); + this.analysis.subscribeList((items, selected) => { + // return if analysis panel is closed or no nodes are loaded + if (!this.token) { + return; + } + + if (selected !== null) { + const updatedNodes: Node[] = []; + for (const item of items) { + const node = this.nodeData.nodes.get(item.id); + if (!node) { + continue; + } + const pos = this.networkHandler.activeNetwork.networkInternal.getPositions([item.id]); + node.x = pos[item.id].x; + node.y = pos[item.id].y; + const isSeed = this.networkHandler.activeNetwork.highlightSeeds ? this.networkHandler.activeNetwork.seedMap[node.id] : false; + const nodeStyled = NetworkSettings.getNodeStyle( + node, + this.drugstoneConfig.currentConfig(), + isSeed, + selected, + this.networkHandler.activeNetwork.getGradient(item.id), + this.networkHandler.activeNetwork.nodeRenderer + ); + updatedNodes.push(nodeStyled); + } + this.nodeData.nodes.update(updatedNodes); + + const proteinSelection = this.tableSelectedProteins; + for (const item of items) { + // TODO: Refactor! + const found = proteinSelection.findIndex((i) => getProteinNodeId(i) === item.id); + const tableItem = this.tableProteins.find((i) => getProteinNodeId(i) === item.id); + if (selected && found === -1 && tableItem) { + proteinSelection.push(tableItem); + } + if (!selected && found !== -1 && tableItem) { + proteinSelection.splice(found, 1); + } + } + this.tableSelectedProteins = [...proteinSelection]; + } else { + // else: selected is null + const updatedNodes = []; + this.nodeData.nodes.forEach((node) => { + const isSeed = this.networkHandler.activeNetwork.highlightSeeds ? this.networkHandler.activeNetwork.seedMap[node.id] : false; + if (!isSeed) { + return; + } + const nodeStyled = NetworkSettings.getNodeStyle( + node, + this.drugstoneConfig.currentConfig(), + isSeed, + selected, + this.networkHandler.activeNetwork.getGradient(node.id), + this.networkHandler.activeNetwork.nodeRenderer + ); + updatedNodes.push(nodeStyled); + }); + this.nodeData.nodes.update(updatedNodes); + + const proteinSelection = []; + for (const item of items) { + const tableItem = this.tableProteins.find((i) => getProteinNodeId(i) === item.id); + if (tableItem) { + proteinSelection.push(tableItem); + } + } + this.tableSelectedProteins = [...proteinSelection]; + } + }); + this.emitVisibleItems(true); + }); + }); + } - if (isBig) { - resolve(nodes); - } - this.networkHandler.activeNetwork.networkInternal.once('stabilizationIterationsDone', async () => { - if (!this.drugstoneConfig.config.physicsOn || this.networkHandler.activeNetwork.isBig()) { - this.networkHandler.activeNetwork.updatePhysicsEnabled(false); - } - this.networkHandler.updateAdjacentNodes(this.networkHandler.activeNetwork.isBig()).then(() => { - resolve(nodes); - }); - }); - }).then(nodes => { - this.tableDrugs = nodes.filter(e => e.drugstoneId && e.drugstoneType === 'drug'); - this.tableDrugs.forEach((r) => { - r.rawScore = r.score; - }); - // @ts-ignore - this.tableDrugs.sort((a, b) => b.score - a.score); - this.rankTable(this.tableDrugs); - this.tableProteins = nodes.filter(e => e.drugstoneId && e.drugstoneType === 'protein'); - this.tableSelectedProteins = []; - this.tableProteins.forEach((r) => { - r.rawScore = r.score; - r.isSeed = this.networkHandler.activeNetwork.seedMap[r.id]; - const wrapper = getWrapperFromNode(r); - if (this.analysis.inSelection(wrapper)) { - this.tableSelectedProteins.push(r); - } - }); - this.tableProteins.sort((a, b) => b.score - a.score); - this.rankTable(this.tableProteins); + private async refreshTask() { + this.loadingScreen.stateUpdate(true); + this.task = await this.getTask(this.token); + this.analysis.switchSelection(this.token); + + if (this.task.info.algorithm === 'degree') { + this.tableDrugScoreTooltip = + 'Normalized number of direct interactions of the drug with the seeds. ' + + 'The higher the score, the more relevant the drug.'; + this.tableProteinScoreTooltip = + 'Normalized number of direct interactions of the protein with the seeds. ' + + 'The higher the score, the more relevant the protein.'; + } else if (this.task.info.algorithm === 'closeness' || this.task.info.algorithm === 'quick' || this.task.info.algorithm === 'super') { + this.tableDrugScoreTooltip = + 'Normalized inverse mean distance of the drug to the seeds. ' + + 'The higher the score, the more relevant the drug.'; + this.tableProteinScoreTooltip = + 'Normalized inverse mean distance of the protein to the seeds. ' + + 'The higher the score, the more relevant the protein.'; + } else if (this.task.info.algorithm === 'trustrank') { + this.tableDrugScoreTooltip = + 'Amount of ‘trust’ on the drug at termination of the algorithm. ' + + 'The higher the score, the more relevant the drug.'; + this.tableProteinScoreTooltip = + 'Amount of ‘trust’ on the protein at termination of the algorithm. ' + + 'The higher the score, the more relevant the protein.'; + } else if (this.task.info.algorithm === 'proximity') { + this.tableDrugScoreTooltip = + 'Empirical z-score of mean minimum distance between the drug’s targets and the seeds. ' + + 'The lower the score, the more relevant the drug.'; + this.tableProteinScoreTooltip = + 'Empirical z-score of mean minimum distance between the drug’s targets and the seeds. ' + + 'The lower the score, the more relevant the drug.'; + } + + if (this.task && this.task.info && this.task.info.done) { + + this.loading = true; + this.netex.getTaskResult(this.token).then(async result => { + this.drugstoneConfig.set_analysisConfig(result.parameters.config); + this.result = result; + if (this.result.parameters.target === 'drug') { + this.legendService.add_to_context('drug'); + } else { + this.legendService.add_to_context('drugTarget'); + } + const nodeAttributes = this.result.nodeAttributes || {}; + + this.networkHandler.activeNetwork.seedMap = nodeAttributes.isSeed || {}; + + // Reset + this.nodeData = {nodes: null, edges: null}; + this.networkHandler.activeNetwork.networkEl.nativeElement.innerHTML = ''; + this.networkHandler.activeNetwork.networkInternal = null; + // Create + await this.createNetwork(this.result).then(nw => { + return new Promise<any>((resolve, reject) => { + + const nodes = nw.nodes; + const edges = nw.edges; + this.networkHandler.activeNetwork.inputNetwork = {nodes: nodes, edges: edges}; + this.nodeData.nodes = new vis.DataSet(nodes); + this.nodeData.edges = new vis.DataSet(edges); + const container = this.networkHandler.activeNetwork.networkEl.nativeElement; + const isBig = nodes.length > 100 || edges.length > 100; + const options = NetworkSettings.getOptions(isBig ? 'analysis-big' : 'analysis', this.drugstoneConfig.currentConfig()); + // @ts-ignore + options.groups = this.drugstoneConfig.currentConfig().nodeGroups; + // @ts-ignore + for (const g of Object.values(options.groups)) { + // @ts-ignore + delete g.renderer; + } + if (this.drugstoneConfig.config.physicsOn) { + this.drugstoneConfig.config.physicsOn = !isBig; + } + this.networkHandler.activeNetwork.networkInternal = new vis.Network(container, this.nodeData, options); - this.tableHasScores = ['trustrank', 'closeness', 'degree', 'betweenness', 'quick', 'super'] - .indexOf(this.task.info.algorithm) !== -1; - if (this.tableHasScores) { - this.toggleNormalization(true); + if (isBig) { + resolve(nodes); + } + this.networkHandler.activeNetwork.networkInternal.once('stabilizationIterationsDone', async () => { + if (!this.drugstoneConfig.config.physicsOn || this.networkHandler.activeNetwork.isBig()) { + this.networkHandler.activeNetwork.updatePhysicsEnabled(false); + } + this.networkHandler.updateAdjacentNodes(this.networkHandler.activeNetwork.isBig()).then(() => { + resolve(nodes); + }); + }); + }).then(nodes => { + + this.tableDrugs = nodes.filter(e => e.drugstoneId && e.drugstoneType === 'drug'); + this.tableDrugs.forEach((r) => { + r.rawScore = r.score; + }); + // @ts-ignore + this.tableDrugs.sort((a, b) => b.score - a.score); + this.rankTable(this.tableDrugs); + this.tableProteins = nodes.filter(e => e.drugstoneId && e.drugstoneType === 'protein'); + this.tableSelectedProteins = []; + this.tableProteins.forEach((r) => { + r.rawScore = r.score; + r.isSeed = this.networkHandler.activeNetwork.seedMap[r.id]; + const wrapper = getWrapperFromNode(r); + if (this.analysis.inSelection(wrapper)) { + this.tableSelectedProteins.push(r); + } + }); + this.tableProteins.sort((a, b) => b.score - a.score); + this.rankTable(this.tableProteins); + + this.tableHasScores = ['trustrank', 'closeness', 'degree', 'betweenness', 'quick', 'super'] + .indexOf(this.task.info.algorithm) !== -1; + if (this.tableHasScores) { + this.toggleNormalization(true); + } + this.networkHandler.activeNetwork.networkInternal.setData({nodes: undefined, edge: undefined}); + setTimeout(() => { + this.networkHandler.activeNetwork.networkInternal.setData(this.nodeData); + }, 1000); + + this.networkHandler.activeNetwork.networkInternal.on('deselectNode', (properties) => { + this.showDetailsChange.emit(null); + }); + + this.networkHandler.activeNetwork.networkInternal.on('doubleClick', (properties) => { + const nodeIds: Array<string> = properties.nodes; + if (nodeIds.length > 0) { + const nodeId = nodeIds[0]; + const node = this.nodeData.nodes.get(nodeId); + if (node.drugstoneId === undefined || node.nodeType === 'drug' || node.drugstoneType !== 'protein') { + this.analysis.unmappedNodeToast(); + return; } - this.networkHandler.activeNetwork.networkInternal.setData({nodes: undefined, edge: undefined}); - setTimeout(() => { - this.networkHandler.activeNetwork.networkInternal.setData(this.nodeData); - }, 1000); + const wrapper = getWrapperFromNode(node); + if (this.analysis.inSelection(wrapper)) { + this.analysis.removeItems([wrapper]); + this.analysis.getCount(); + } else { + this.analysis.addItems([wrapper]); + this.analysis.getCount(); + } + } + }); - this.networkHandler.activeNetwork.networkInternal.on('deselectNode', (properties) => { + this.networkHandler.activeNetwork.networkInternal.on('click', (properties) => { + if (properties.nodes.length === 0 && properties.edges.length === 1) { + // clicked on one edge + const edgeId = properties.edges[0]; + this.networkHandler.activeNetwork.openEdgeSummary(edgeId); + } else { + this.networkHandler.activeNetwork.activeEdge = null; + const selectedNodes = this.nodeData.nodes.get(properties.nodes); + if (selectedNodes.length > 0) { + this.showDetailsChange.emit(getWrapperFromNode(selectedNodes[0])); + } else { this.showDetailsChange.emit(null); - }); + } + } + }); - this.networkHandler.activeNetwork.networkInternal.on('doubleClick', (properties) => { - const nodeIds: Array<string> = properties.nodes; - if (nodeIds.length > 0) { - const nodeId = nodeIds[0]; - const node = this.nodeData.nodes.get(nodeId); - if (node.drugstoneId === undefined || node.nodeType === 'drug' || node.drugstoneType !== 'protein') { - this.analysis.unmappedNodeToast(); - return; - } - const wrapper = getWrapperFromNode(node); - if (this.analysis.inSelection(wrapper)) { - this.analysis.removeItems([wrapper]); - this.analysis.getCount(); - } else { - this.analysis.addItems([wrapper]); - this.analysis.getCount(); - } + this.analysis.subscribeList((items, selected) => { + // return if analysis panel is closed or no nodes are loaded + if (!this.token) { + return; + } + + if (selected !== null) { + const updatedNodes: Node[] = []; + for (const item of items) { + const node = this.nodeData.nodes.get(item.id); + if (!node) { + continue; } - }); - - this.networkHandler.activeNetwork.networkInternal.on('click', (properties) => { - if (properties.nodes.length === 0 && properties.edges.length === 1) { - // clicked on one edge - const edgeId = properties.edges[0]; - this.networkHandler.activeNetwork.openEdgeSummary(edgeId); - } else { - this.networkHandler.activeNetwork.activeEdge = null; - const selectedNodes = this.nodeData.nodes.get(properties.nodes); - if (selectedNodes.length > 0) { - this.showDetailsChange.emit(getWrapperFromNode(selectedNodes[0])); - } else { - this.showDetailsChange.emit(null); - } + const pos = this.networkHandler.activeNetwork.networkInternal.getPositions([item.id]); + node.x = pos[item.id].x; + node.y = pos[item.id].y; + const isSeed = this.networkHandler.activeNetwork.highlightSeeds ? this.networkHandler.activeNetwork.seedMap[node.id] : false; + const nodeStyled = NetworkSettings.getNodeStyle( + node, + this.drugstoneConfig.currentConfig(), + isSeed, + selected, + this.networkHandler.activeNetwork.getGradient(item.id), + this.networkHandler.activeNetwork.nodeRenderer + ); + updatedNodes.push(nodeStyled); + } + this.nodeData.nodes.update(updatedNodes); + + const proteinSelection = this.tableSelectedProteins; + for (const item of items) { + // TODO: Refactor! + const found = proteinSelection.findIndex((i) => getProteinNodeId(i) === item.id); + const tableItem = this.tableProteins.find((i) => getProteinNodeId(i) === item.id); + if (selected && found === -1 && tableItem) { + proteinSelection.push(tableItem); } - }); - - this.analysis.subscribeList((items, selected) => { - // return if analysis panel is closed or no nodes are loaded - if (!this.token) { + if (!selected && found !== -1 && tableItem) { + proteinSelection.splice(found, 1); + } + } + this.tableSelectedProteins = [...proteinSelection]; + } else { + // else: selected is null + const updatedNodes = []; + this.nodeData.nodes.forEach((node) => { + const isSeed = this.networkHandler.activeNetwork.highlightSeeds ? this.networkHandler.activeNetwork.seedMap[node.id] : false; + if (!isSeed) { return; } + const nodeStyled = NetworkSettings.getNodeStyle( + node, + this.drugstoneConfig.currentConfig(), + isSeed, + selected, + this.networkHandler.activeNetwork.getGradient(node.id), + this.networkHandler.activeNetwork.nodeRenderer + ); + updatedNodes.push(nodeStyled); + }); + this.nodeData.nodes.update(updatedNodes); - if (selected !== null) { - const updatedNodes: Node[] = []; - for (const item of items) { - const node = this.nodeData.nodes.get(item.id); - if (!node) { - continue; - } - const pos = this.networkHandler.activeNetwork.networkInternal.getPositions([item.id]); - node.x = pos[item.id].x; - node.y = pos[item.id].y; - const isSeed = this.networkHandler.activeNetwork.highlightSeeds ? this.networkHandler.activeNetwork.seedMap[node.id] : false; - const nodeStyled = NetworkSettings.getNodeStyle( - node, - this.drugstoneConfig.currentConfig(), - isSeed, - selected, - this.networkHandler.activeNetwork.getGradient(item.id), - this.networkHandler.activeNetwork.nodeRenderer - ); - updatedNodes.push(nodeStyled); - } - this.nodeData.nodes.update(updatedNodes); - - const proteinSelection = this.tableSelectedProteins; - for (const item of items) { - // TODO: Refactor! - const found = proteinSelection.findIndex((i) => getProteinNodeId(i) === item.id); - const tableItem = this.tableProteins.find((i) => getProteinNodeId(i) === item.id); - if (selected && found === -1 && tableItem) { - proteinSelection.push(tableItem); - } - if (!selected && found !== -1 && tableItem) { - proteinSelection.splice(found, 1); - } - } - this.tableSelectedProteins = [...proteinSelection]; - } else { - // else: selected is null - const updatedNodes = []; - this.nodeData.nodes.forEach((node) => { - const isSeed = this.networkHandler.activeNetwork.highlightSeeds ? this.networkHandler.activeNetwork.seedMap[node.id] : false; - if (!isSeed) { - return; - } - const nodeStyled = NetworkSettings.getNodeStyle( - node, - this.drugstoneConfig.currentConfig(), - isSeed, - selected, - this.networkHandler.activeNetwork.getGradient(node.id), - this.networkHandler.activeNetwork.nodeRenderer - ); - updatedNodes.push(nodeStyled); - }); - this.nodeData.nodes.update(updatedNodes); - - const proteinSelection = []; - for (const item of items) { - const tableItem = this.tableProteins.find((i) => getProteinNodeId(i) === item.id); - if (tableItem) { - proteinSelection.push(tableItem); - } - } - this.tableSelectedProteins = [...proteinSelection]; + const proteinSelection = []; + for (const item of items) { + const tableItem = this.tableProteins.find((i) => getProteinNodeId(i) === item.id); + if (tableItem) { + proteinSelection.push(tableItem); } - }); - this.emitVisibleItems(true); - }).then(() => { - if (!['quick', 'super', 'connect', 'connectSelected'].includes(this.task.info.algorithm)) { - return; } - this.netex.getAlgorithmDefaults(this.task.info.algorithm).then(response => { - this.algorithmDefault = response; - }); - }).catch(console.error); + this.tableSelectedProteins = [...proteinSelection]; + } }); - this.loadingScreen.stateUpdate(false); - }); - } - } + this.emitVisibleItems(true); + }).then(() => { + if (!['quick', 'super', 'connect', 'connectSelected'].includes(this.task.info.algorithm)) { + return; + } + this.netex.getAlgorithmDefaults(this.task.info.algorithm).then(response => { + this.algorithmDefault = response; + }); + }).catch(console.error); + }); + this.loadingScreen.stateUpdate(false); + }); } + } + private async refresh() { + if (this.token) { + if (this.tokenType === 'view') { + await this.refreshView(); + } else { + await this.refreshTask(); + } + } } diff --git a/src/app/components/analysis-panel/view-list/view-list.component.html b/src/app/components/analysis-panel/view-list/view-list.component.html index f9d5b9328fd8bc48afefaac85322e7ce53e37fdf..0ed31cf8ff8a553d28f57cb23981424b5480af2e 100644 --- a/src/app/components/analysis-panel/view-list/view-list.component.html +++ b/src/app/components/analysis-panel/view-list/view-list.component.html @@ -4,50 +4,19 @@ [ngClass]="{ 'text-normal': drugstoneConfig.smallStyle }" > <a - *ngFor="let task of analysis.selectionTokens" + *ngFor="let task of analysis.viewInfos" class="list-item box small-box" - [class.is-active]="task === token" + [class.is-active]="task.token === token" > -<!-- <div *ngIf="!task">--> -<!-- <div class="columns mb-0">--> -<!-- <div class="column">--> -<!-- <app-fa-solid-icon--> -<!-- classString="is-pulled-right has-text-warning"--> -<!-- icon="pause"--> -<!-- ></app-fa-solid-icon>--> -<!-- </div>--> -<!-- </div>--> -<!-- <div class="columns mb-0">--> -<!-- <div class="column pt-0 pb-0">--> -<!-- <a--> -<!-- (click)="analysis.removeSelection(task)"--> -<!-- class="has-text-danger is-pulled-right"--> -<!-- >--> -<!-- <app-fa-solid-icon icon="trash"></app-fa-solid-icon>--> -<!-- </a>--> -<!-- </div>--> -<!-- </div>--> -<!-- </div>--> <div *ngIf="task" - (click)="open(task)" + (click)="open(task.token)" pTooltip="Show selection view" [tooltipStyleClass]="'drgstn drgstn-tooltip drgstn-tooltip-top'" tooltipPosition="top" > <div class="columns mb-0"> <div class="column is-8"> -<!-- <span class="is-capitalized"--> -<!-- ><app-fa-solid-icon--> -<!-- icon="crosshairs"--> -<!-- *ngIf="task.info.target === 'drug-target'"--> -<!-- ></app-fa-solid-icon>--> -<!-- <app-fa-solid-icon--> -<!-- icon="capsules"--> -<!-- *ngIf="task.info.target === 'drug'"--> -<!-- ></app-fa-solid-icon>--> -<!-- {{ algorithmNames[task.info.algorithm] }}</span--> -<!-- >--> </div> <div class="column"> <app-fa-solid-icon @@ -57,9 +26,9 @@ </div> </div> <div class="columns mb-0"> -<!-- <div class="column is-8 pt-0 pb-0">--> -<!-- <small>Created {{ task.info.finishedAt | date: "short" }}</small>--> -<!-- </div>--> + <div class="column is-8 pt-0 pb-0"> + <small>Created {{ task.createdAt | date: "short" }}</small> + </div> <div class="column pt-0 pb-0"> <a (click)="analysis.removeTask(task)" diff --git a/src/app/pages/explorer-page/explorer-page.component.html b/src/app/pages/explorer-page/explorer-page.component.html index 9f3269d43300c8d7c3556caeb5ff88b183ed4a8a..f8541ecd93e0094528c3b485c42ccd14048c6a94 100644 --- a/src/app/pages/explorer-page/explorer-page.component.html +++ b/src/app/pages/explorer-page/explorer-page.component.html @@ -422,7 +422,16 @@ pTooltip="Add all proteins to the selection." > <app-fa-solid-icon icon="plus"></app-fa-solid-icon> - <span> Add all </span> + <span>Add all</span> + </a> + <a + (click)="analysis.addFirstNeighbors()" + class="card-footer-item text-primary" + tooltipPosition="top" + pTooltip="Add first neighbor proteins of selection to selection." + > + <app-fa-solid-icon icon="plus"></app-fa-solid-icon> + <span>Add First neighbors</span> </a> </footer> <footer class="card-footer"> @@ -456,24 +465,27 @@ </a> <a *ngIf="analysis.getSelection().length" - (click)="analysis.resetSelection()" - class="card-footer-item has-text-danger" + (click)="analysis.viewFromSelection()" + class="card-footer-item text-primary" tooltipPosition="top" - pTooltip="Remove all entries from the selection." + pTooltip="Create view from the selection." > - <app-fa-solid-icon icon="broom"></app-fa-solid-icon> - <span> Reset </span> + <app-fa-solid-icon icon="check"></app-fa-solid-icon> + <span> Save selection </span> </a> + </footer> + <footer class="card-footer"> <a *ngIf="analysis.getSelection().length" - (click)="analysis.viewFromSelection()" + (click)="analysis.resetSelection()" class="card-footer-item has-text-danger" tooltipPosition="top" - pTooltip="Create view from the selection." + pTooltip="Remove all entries from the selection." > - <app-fa-solid-icon icon="check"></app-fa-solid-icon> - <span> Save selection </span> + <app-fa-solid-icon icon="broom"></app-fa-solid-icon> + <span> Reset </span> </a> + </footer> <!-- </div> --> @@ -487,7 +499,7 @@ > <p class="card-header-title"> <app-fa-solid-icon icon="tasks"></app-fa-solid-icon> - Views ({{ analysis.selectionTokens != null ? analysis.selectionTokens.length : 0 }}) + Views ({{ analysis.viewTokens != null ? analysis.viewTokens.length : 0 }}) </p> <a (click)="collapseViews = !collapseViews" @@ -508,13 +520,13 @@ <div *ngIf="collapseViews"> <div class="card-content overflow task-list-container" - *ngIf="analysis.selectionTokens && analysis.selectionTokens.length > 0" + *ngIf="analysis.viewTokens && analysis.viewTokens.length > 0" > <app-view-list [(token)]="selectedViewToken"></app-view-list> </div> <footer class="card-footer"> <a - *ngIf="analysis.selectionTokens && analysis.selectionTokens.length > 0" + *ngIf="analysis.viewTokens && analysis.viewTokens.length > 0" (click)=" analysis.removeAllSelections(); selectedViewToken = null " diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts index c316d55e34e10ab401ef494308a9fab1f3c5673f..cbb95cd844cf3ba46f5d00b4c98db60d9b00cd49 100644 --- a/src/app/pages/explorer-page/explorer-page.component.ts +++ b/src/app/pages/explorer-page/explorer-page.component.ts @@ -405,11 +405,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { }); - // if (!this.drugstoneConfig.config.showSidebar) { - // // skip network options for selecting nodes when there are no options to use it - // return; - // } - this.networkHandler.activeNetwork.networkInternal.on('doubleClick', (properties) => { const nodeIds: Array<string> = properties.nodes; if (nodeIds != null && nodeIds.length > 0) { @@ -532,6 +527,67 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { this.drugstoneConfig.smallStyle = this.windowWidth < 1250; } + public initNetworkListeners(resolve){ + this.networkHandler.activeNetwork.networkInternal.on('doubleClick', (properties) => { + const nodeIds: Array<string> = properties.nodes; + if (nodeIds != null && nodeIds.length > 0) { + const nodeId = nodeIds[0]; + const node = this.nodeData.nodes.get(nodeId); + if (node.drugstoneId === undefined || node.drugstoneType !== 'protein') { + this.analysis.unmappedNodeToast(); + // skip if node is not a protein mapped to backend + return; + } + const wrapper = getWrapperFromNode(node); + if (this.analysis.inSelection(node)) { + this.analysis.removeItems([wrapper]); + } else { + this.analysis.addItems([wrapper]); + } + } + }); + + this.networkHandler.activeNetwork.networkInternal.on('click', (properties) => { + if (properties.nodes.length === 0 && properties.edges.length === 1) { + // clicked on one edge + const edgeId = properties.edges[0]; + this.networkHandler.activeNetwork.openEdgeSummary(edgeId); + } else { + // clicked not on one edge + const nodeIds: Array<string> = properties.nodes; + if (nodeIds != null && nodeIds.length > 0) { + const nodeId = nodeIds[0]; + const node = this.nodeData.nodes.get(nodeId); + const wrapper = getWrapperFromNode(node); + this.openNodeSummary(wrapper, false); + } else { + this.closeSummary(); + } + } + }); + + this.networkHandler.activeNetwork.networkInternal.on('deselectNode', (properties) => { + this.closeSummary(); + }); + + if (this.networkHandler.activeNetwork.selectedWrapper) { + this.zoomToNode(this.networkHandler.activeNetwork.selectedWrapper.id); + } + + this.networkHandler.activeNetwork.currentViewNodes = this.nodeData.nodes; + this.networkHandler.activeNetwork.currentViewEdges = this.nodeData.edges; + + this.networkHandler.activeNetwork.queryItems = []; + this.networkHandler.activeNetwork.updateQueryItems(); + this.networkHandler.activeNetwork.currentViewProteins = this.networkHandler.activeNetwork.inputNetwork.nodes; + // this.fillQueryItems(this.currentViewNodes); + if (this.networkHandler.activeNetwork.selectedWrapper) { + this.networkHandler.activeNetwork.networkInternal.selectNodes([this.networkHandler.activeNetwork.selectedWrapper.id]); + } + + resolve(true); + } + public async openNodeSummary(item: Wrapper, zoom: boolean) { // close edge summary if open this.networkHandler.activeNetwork.activeEdge = null; diff --git a/src/app/services/analysis/analysis.service.ts b/src/app/services/analysis/analysis.service.ts index 81422449af3b923fe79ecc71bb0374ca831aaaf3..d68cc591a3f607366a4975f5d790f058d54cb76f 100644 --- a/src/app/services/analysis/analysis.service.ts +++ b/src/app/services/analysis/analysis.service.ts @@ -61,7 +61,8 @@ export class AnalysisService { private selections = new Map<string, Map<string, Wrapper>>(); public tokens: string[] = []; - public selectionTokens: string[] = []; + public viewTokens: string[] = []; + public viewInfos = []; private tokensCookieKey = `drugstone-tokens-${window.location.host}`; private selectionsCookieKey = `drugstone-selections-${window.location.host}`; private tokensFinishedCookieKey = `drugstone-finishedTokens-${window.location.host}`; @@ -90,8 +91,8 @@ export class AnalysisService { this.tokens = JSON.parse(tokens); } if (selections) { - this.selectionTokens = JSON.parse(selections); - console.log(this.selectionTokens); + this.viewTokens = JSON.parse(selections); + this.setViewInfos(); } if (finishedTokens) { this.finishedTokens = JSON.parse(finishedTokens); @@ -103,6 +104,21 @@ export class AnalysisService { }); } + setViewInfos(): void { + this.netex.getViewInfos(this.viewTokens).then(res => { + // @ts-ignore + this.viewInfos = res.reverse(); + }); + } + + removeAnalysis(token, type) { + if (type !== 'view') { + this.removeTask(token); + } else { + this.removeView(token); + } + } + removeTask(token) { this.tokens = this.tokens.filter((item) => item !== token); this.finishedTokens = this.finishedTokens.filter((item) => item !== token); @@ -110,9 +126,10 @@ export class AnalysisService { localStorage.setItem(this.tokensCookieKey, JSON.stringify(this.tokens)); } - removeSelection(token) { - this.selectionTokens = this.selectionTokens.filter((item) => item !== token); - localStorage.setItem(this.selectionsCookieKey, JSON.stringify(this.selectionTokens)); + removeView(token) { + this.viewTokens = this.viewTokens.filter((item) => item !== token); + localStorage.setItem(this.selectionsCookieKey, JSON.stringify(this.viewTokens)); + this.setViewInfos(); } removeAllTasks() { @@ -123,7 +140,8 @@ export class AnalysisService { } removeAllSelections() { - this.selectionTokens = []; + this.viewTokens = []; + this.viewInfos = []; localStorage.removeItem(this.selectionsCookieKey); } @@ -195,6 +213,33 @@ export class AnalysisService { } } + + // Adds first neighbors of selected nodes to selection + public addFirstNeighbors() { + const wrappers: Wrapper[] = []; + const mappedNodes = {}; + this.networkHandler.activeNetwork.currentViewNodes.forEach((node) => { + if (node.drugstoneType === 'protein' && node.drugstoneId) { + mappedNodes[node.label] = node; + } + }); + const selectedNodes = new Set(this.selectedItems.keys()); + const firstNeighborNodes: Set<string> = new Set(); + this.networkHandler.activeNetwork.currentViewEdges.forEach(edge => { + if (selectedNodes.has(edge.from)) { + firstNeighborNodes.add(edge.to); + } + if (selectedNodes.has(edge.to)) { + firstNeighborNodes.add(edge.from); + } + }); + + firstNeighborNodes.forEach(n => { + wrappers.push(getWrapperFromNode(mappedNodes[n])); + }); + this.addItems(wrappers); + } + public addAllToSelection() { const wrappers: Wrapper[] = []; const unmappedNodes = []; @@ -281,10 +326,9 @@ export class AnalysisService { }; const resp = await this.http.post<any>(`${this.netex.getBackend()}save_selection`, payload).toPromise(); // @ts-ignore - console.log(resp.token); - // @ts-ignore - this.selectionTokens.push(resp.token); - localStorage.setItem(this.selectionsCookieKey, JSON.stringify(this.selectionTokens)); + this.viewTokens.push(resp.token); + this.setViewInfos(); + localStorage.setItem(this.selectionsCookieKey, JSON.stringify(this.viewTokens)); this.toast.setNewToast({ message: 'Analysis task started. This may take a while. ' + diff --git a/src/app/services/netex-controller/netex-controller.service.ts b/src/app/services/netex-controller/netex-controller.service.ts index f87da76ae1993f376147871372adae7a7cc330de..4d8364d7d0a1138340f5fb0ed67bb5cdf8e5d206 100644 --- a/src/app/services/netex-controller/netex-controller.service.ts +++ b/src/app/services/netex-controller/netex-controller.service.ts @@ -132,4 +132,9 @@ export class NetexControllerService { */ return this.http.get(`${this.getBackend()}get_license`).toPromise(); } + + public async getViewInfos(tokens) { + return await this.http.post(`${this.getBackend()}view_infos`, {tokens}).toPromise(); + } + }