diff --git a/client/client/app/components/ngbPathways/ngbCytoscapePathway/ngbCytoscapePathway.controller.js b/client/client/app/components/ngbPathways/ngbCytoscapePathway/ngbCytoscapePathway.controller.js index f842bd961..3fd89dd93 100644 --- a/client/client/app/components/ngbPathways/ngbCytoscapePathway/ngbCytoscapePathway.controller.js +++ b/client/client/app/components/ngbPathways/ngbCytoscapePathway/ngbCytoscapePathway.controller.js @@ -6,10 +6,6 @@ const sbgnStylesheet = require('cytoscape-sbgn-stylesheet'); const $ = require('jquery'); const SCALE = 0.3; -const elementOptionsType = { - NODE: 'nodes', - EDGE: 'edges' -}; export default class ngbCytoscapePathwayController { constructor($element, $scope, $compile, $window, $timeout, dispatcher, cytoscapeSettings) { @@ -71,27 +67,25 @@ export default class ngbCytoscapePathwayController { } this.$timeout(() => { const sbgnStyle = sbgnStylesheet(Cytoscape); - // Object.keys(sbgnStyle).forEach(key => { - // if(sbgnStyle[key].selector === 'edge') { - // Object.keys(sbgnStyle[key].properties).forEach(propKey => { - // if(sbgnStyle[key].properties[propKey].name === 'curve-style') { - // sbgnStyle[key].properties[propKey].value = 'taxi'; - // } - // }); - // } - // }); - // sbgnStyle.edge['curve-style'] = 'taxi'; - // const savedState = JSON.parse(localStorage.getItem(this.storageName) || '{}'); - // const savedLayout = savedState.layout ? savedState.layout[this.elements.id] : undefined; - // let elements, layoutSettings; + const savedState = JSON.parse(localStorage.getItem(this.storageName) || '{}'); + const savedLayout = savedState.layout ? savedState.layout[this.elements.id] : undefined; + let elements; + if (savedLayout) { + elements = { + nodes: this.getPlainNodes(savedLayout.nodes), + edges: savedLayout.edges + }; + } else { + elements = { + nodes: this.positionedNodes(this.elements.nodes), + edges: this.elements.edges + }; + } this.viewer = Cytoscape({ container: this.cytoscapeContainer, style: sbgnStyle, layout: {name: 'preset'}, - elements: { - nodes: this.positionedNodes(this.elements.nodes), - edges: this.elements.edges, - }, + elements: elements, }); const layout = this.viewer.layout(this.settings.loadedLayout); layout.on('layoutready', () => { @@ -120,7 +114,7 @@ export default class ngbCytoscapePathwayController { layout.run(); const viewerContext = this; this.actionsManager = { - ZOOM_STEP: 0.25, + ZOOM_STEP: 0.125, duration: 250, zoom: () => viewerContext.viewer.zoom(), zoomIn() { @@ -137,6 +131,16 @@ export default class ngbCytoscapePathwayController { this.canZoomIn = zoom < viewerContext.viewer.maxZoom(); this.canZoomOut = zoom > viewerContext.viewer.minZoom(); }, + restoreDefault: () => { + this.viewer.batch(() => { + this.viewer.remove(this.viewer.nodes()); + this.viewer.remove(this.viewer.edges()); + this.viewer.add(this.positionedNodes(this.elements.nodes)); + this.viewer.add(this.elements.edges); + }); + // viewerContext.viewer.layout(this.settings.defaultLayout).run(); + viewerContext.saveLayout(); + }, canZoomIn: true, canZoomOut: true, ready: true @@ -195,32 +199,12 @@ export default class ngbCytoscapePathwayController { }, []); } - applyOptions(elements, type) { - if (!this.elementsOptions) { - return; - } - switch (type) { - case elementOptionsType.NODE: { - return elements.reduce((r, cv) => { - if (this.elementsOptions.nodes[cv.data.id]) { - cv.data = { - ...cv.data, - ...this.elementsOptions.nodes[cv.data.id] - }; - } - r.push(cv); - return r; - }, []); - } - } - } - positionedNodes(nodes) { nodes.forEach(node => { if (node.data.bbox) { node.position = { - x: node.data.bbox.x/SCALE, - y: node.data.bbox.y/SCALE + x: node.data.bbox.x / SCALE, + y: node.data.bbox.y / SCALE }; } }); diff --git a/client/client/app/components/ngbPathways/ngbCytoscapePathway/ngbCytoscapePathway.settings.js b/client/client/app/components/ngbPathways/ngbCytoscapePathway/ngbCytoscapePathway.settings.js index 4347a89de..2cc400569 100644 --- a/client/client/app/components/ngbPathways/ngbCytoscapePathway/ngbCytoscapePathway.settings.js +++ b/client/client/app/components/ngbPathways/ngbCytoscapePathway/ngbCytoscapePathway.settings.js @@ -1,42 +1,6 @@ export default { viewer: {}, - style: { - node: { - 'content': 'data(id)', - 'width': 175, - 'height': 60, - 'text-opacity': 1, - 'text-valign': 'center', - 'text-halign': 'center', - 'shape': 'rectangle', - 'label': 'data(id)', - 'background-opacity': 0, - 'opacity': 0, - 'color': '#000', - 'border-width': 1 - }, - edge: { - 'curve-style': 'bezier', - 'width': 1, - 'line-color': '#37474F', - 'target-arrow-color': '#37474F', - 'target-arrow-shape': 'triangle', - 'overlay-color': '#4285F4', - 'overlay-padding': '4px', - 'underlay-color': '#4285F4', - 'underlay-padding': '3px', - 'underlay-opacity': '0' - }, - edgeLabel: { - 'text-rotation': 'none', - 'content': 'data(label)', - 'font-size': '12px', - 'font-weight': 'bold', - 'text-background-color': '#fff', - 'text-background-opacity': 1, - 'color': '#2c4f9e' - } - }, + style: {}, defaultLayout: { name: 'dagre', rankDir: 'TB' diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.controller.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.controller.js index ab1af1b39..d9eaecb4a 100644 --- a/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.controller.js +++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.controller.js @@ -47,16 +47,15 @@ export default class ngbInternalPathwaysResultController extends baseController } async initialize() { - if (!this.ngbPathwaysService.currentInternalPathwaysId) { + if (!this.ngbPathwaysService.currentInternalPathway) { return; } - const {data, error} = await this.ngbInternalPathwaysResultService.getPathwayTreeById(this.ngbPathwaysService.currentInternalPathwaysId); + const {data, error} = await this.ngbInternalPathwaysResultService.getPathwayTree(this.ngbPathwaysService.currentInternalPathway); if (error) { this.treeError = error; } else { this.treeError = false; - this.selectedTree = data.tree; - this.selectedTreeName = data.name; + this.selectedTree = data; } this.loading = false; this.$timeout(() => this.$scope.$apply()); diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.scss b/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.scss index 149b7c7ea..bf544dfca 100644 --- a/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.scss +++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.scss @@ -1,8 +1,6 @@ -.ngb-cytoscape-container { - width: 100%; - height: 100%; - min-height: 500px; +.ngb-pathway-cytoscape-container { flex: 1; + position: relative; } .internal-pathway-container-error { @@ -11,7 +9,7 @@ } .internal-pathway-container { - margin: 2px 10px; + margin: 2px 0; height: calc(100% - 4px); display: flex; flex-direction: column; diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.service.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.service.js index 2edd80759..5211cc21c 100644 --- a/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.service.js +++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.service.js @@ -1,7 +1,4 @@ export default class ngbInternalPathwaysResultService { - - currentReferenceId = null; - constructor(genomeDataService, dispatcher) { this.dispatcher = dispatcher; this.genomeDataService = genomeDataService; @@ -11,24 +8,22 @@ export default class ngbInternalPathwaysResultService { return new ngbInternalPathwaysResultService(genomeDataService, dispatcher); } - async getPathwayTreeById(id) { - if(!id) { + async getPathwayTree(treeConfig) { + if(!treeConfig.id) { return { data: null, error: false }; } - const xml = require(`./xml/${id}.xml`); + const xml = await this.genomeDataService.loadPathwayFileById(treeConfig.id); try { const convert = require('sbgnml-to-cytoscape'); const data = convert(xml); + data.id = treeConfig.id; + data.name = treeConfig.name; if (data) { - data.id = id; return { - data: { - name: id, - tree: data - }, + data: data, error: false }; } else { diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.tpl.html b/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.tpl.html index e4374fa4b..170a8ea8b 100644 --- a/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.tpl.html +++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysResult/ngbInternalPathwaysResult.tpl.html @@ -4,7 +4,7 @@ -
+
- {{$ctrl.selectedTreeName}} + {{$ctrl.selectedTree.name}}
-
+
{{$ctrl.treeError}}
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.controller.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.controller.js index 419d052cb..683909ce9 100644 --- a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.controller.js +++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.controller.js @@ -7,7 +7,6 @@ const RESIZE_DELAY = 300; export default class ngbInternalPathwaysTableController extends baseController { dispatcher; isProgressShown = true; - isEmptyResult = false; errorMessageList = []; debounce = (new Debounce()).debounce; gridOptions = { @@ -39,7 +38,7 @@ export default class ngbInternalPathwaysTableController extends baseController { }; events = { 'pathways:internalPathways:page:change': this.loadData.bind(this), - 'pathways:internalPathways:search': this.loadData.bind(this), + 'pathways:internalPathways:search': this.initialize.bind(this), 'read:show:pathways': this.loadData.bind(this) }; @@ -87,10 +86,10 @@ export default class ngbInternalPathwaysTableController extends baseController { } }); await this.loadData(); + this.isProgressShown = false; } async loadData() { - this.isProgressShown = true; try { await this.ngbInternalPathwaysTableService.searchInternalPathways(this.ngbPathwaysService.currentSearch); const dataLength = this.ngbInternalPathwaysTableService.internalPathways.length; @@ -106,9 +105,7 @@ export default class ngbInternalPathwaysTableController extends baseController { } else { this.isEmptyResults = true; } - this.isProgressShown = false; } catch (errorObj) { - this.isProgressShown = false; this.onError(errorObj.message); } this.$timeout(() => this.$scope.$apply()); @@ -121,7 +118,10 @@ export default class ngbInternalPathwaysTableController extends baseController { rowClick(row, event) { const entity = row.entity; if (entity) { - this.ngbPathwaysService.currentInternalPathwaysId = row.entity.xml; + this.ngbPathwaysService.currentInternalPathway = { + id: row.entity.id, + name: row.entity.name + }; this.changeState({state: 'INTERNAL_PATHWAYS_RESULT'}); } else { event.stopImmediatePropagation(); @@ -136,7 +136,7 @@ export default class ngbInternalPathwaysTableController extends baseController { const {columns} = this.gridApi.saveState.save(); const fieldTitleMap = ( o => Object.keys(o).reduce( - (r, k) => Object.assign(r, { [o[k]]: k }), {} + (r, k) => Object.assign(r, {[o[k]]: k}), {} ) )(this.ngbInternalPathwaysTableService.columnTitleMap); const mapNameToField = function ({name}) { diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.service.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.service.js index cd7b91eaa..2bb558d67 100644 --- a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.service.js +++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.service.js @@ -1,5 +1,4 @@ import ClientPaginationService from '../../../shared/services/clientPaginationService'; -import {calculateColor} from '../../../shared/utils/calculateColor'; const DEFAULT_INTERNAL_PATHWAYS_COLUMNS = [ 'name', 'description' @@ -13,12 +12,9 @@ const INTERNAL_PATHWAYS_COLUMN_TITLES = { description: 'Description' }; const FIRST_PAGE = 1; -const PAGE_SIZE = 15; +const PAGE_SIZE = 11; export default class ngbInternalPathwaysTableService extends ClientPaginationService { - - _internalPathwaysResult; - constructor(dispatcher, genomeDataService) { super(dispatcher, FIRST_PAGE, PAGE_SIZE, 'pathways:internalPathways:page:change'); this.dispatcher = dispatcher; @@ -60,30 +56,18 @@ export default class ngbInternalPathwaysTableService extends ClientPaginationSer return new ngbInternalPathwaysTableService(dispatcher, genomeDataService); } - getInternalPathwaysResultById(id) { - return this._internalPathwaysResult[id]; - } - - getInternalPathwaysById(id) { - return this.internalPathways.filter(h => h.groupId === id)[0] || {}; - } - async searchInternalPathways(currentSearch) { - const result = await this.loadInternalPathways(currentSearch); - this._internalPathways = result.internalPathways; - this._internalPathwaysResult = result.internalPathwaysResult; + this._internalPathways = await this.loadInternalPathways(currentSearch); this.dispatcher.emitSimpleEvent('internalPathways:result:change'); } async loadInternalPathways(currentSearch) { - const emptyResult = { - internalPathways: [], - internalPathwaysResult: {} - }; const filter = { - query: currentSearch, - page: this.currentPage, - pageSize: this.pageSize + pagingInfo: { + pageSize: this.pageSize, + pageNum: this.currentPage + }, + sortInfos: this.orderBy }; const data = await this.genomeDataService.getInternalPathwaysLoad(filter); if (data.error) { @@ -91,58 +75,22 @@ export default class ngbInternalPathwaysTableService extends ClientPaginationSer this.currentPage = FIRST_PAGE; this._firstPage = FIRST_PAGE; this._pageError = data.message; - return emptyResult; + return []; } else { this._pageError = null; } this.totalPages = Math.ceil(data.totalCount / this.pageSize); if (data && data.items) { - return { - internalPathways: this.getInternalPathwaysSearch(data.items), - internalPathwaysResult: this.getInternalPathwaysResult(data.items) - }; + return data.items.map(this._formatServerToClient); } else { - return emptyResult; + return []; } } - getInternalPathwaysSearch(data) { - const result = []; - data.forEach(value => result.push(this._formatServerToClient(value))); - return result; - } - - getInternalPathwaysResult(data) { - return data; - let maxHomologLength = 0; - const result = {}; - if (data) { - data.forEach(internalPathways => { - maxHomologLength = 0; - result[internalPathways.groupId] = []; - internalPathways.genes.forEach((gene, key) => { - result[internalPathways.groupId][key] = this._formatResultToClient(gene); - if (maxHomologLength < result[internalPathways.groupId][key].aa) { - maxHomologLength = result[internalPathways.groupId][key].aa; - } - }); - result[internalPathways.groupId].forEach((value, key) => { - result[internalPathways.groupId][key].domainsObj = { - domains: value.domains.map(d => ({...d, color: calculateColor(d.name)})), - homologLength: value.aa, - maxHomologLength: maxHomologLength, - accession_id: value.accession_id - }; - delete result[internalPathways.groupId][key].domains; - }); - }); - } - return result; - } - getInternalPathwaysGridColumns() { const result = []; const columnsList = this.internalPathwaysColumns; + const headerCells = require('./ngbInternalPathwaysTable_header.tpl.html'); for (let i = 0; i < columnsList.length; i++) { let sortDirection = 0; let sortingPriority = 0; @@ -162,8 +110,9 @@ export default class ngbInternalPathwaysTableService extends ClientPaginationSer cellTemplate: ``, enableHiding: false, - enableColumnMenu: false, + enableSorting: true, field: 'name', + headerCellTemplate: headerCells, name: this.columnTitleMap[column] }; break; @@ -171,9 +120,9 @@ export default class ngbInternalPathwaysTableService extends ClientPaginationSer default: { columnSettings = { enableHiding: false, - enableColumnMenu: false, field: column, minWidth: 40, + headerCellTemplate: headerCells, name: this.columnTitleMap[column], width: '*' }; @@ -194,52 +143,10 @@ export default class ngbInternalPathwaysTableService extends ClientPaginationSer } _formatServerToClient(internalPathways) { - return internalPathways; - const gene = new Set(); - const proteinFrequency = {}; - internalPathways.genes.forEach(g => { - gene.add(g.symbol); - if (proteinFrequency.hasOwnProperty(g.title)) { - proteinFrequency[g.title] += 1; - } else { - proteinFrequency[g.title] = 1; - } - }); - - const sortableProteinFrequency = []; - for (const protein in proteinFrequency) { - if (proteinFrequency.hasOwnProperty(protein)) { - sortableProteinFrequency.push([protein, proteinFrequency[protein]]); - } - } - - sortableProteinFrequency.sort((b, a) => a[1] - b[1]); - - return { - groupId: internalPathways.groupId, - gene: [...gene].sort().join(', '), - protein: sortableProteinFrequency[0] ? sortableProteinFrequency[0][0] : '', - info: internalPathways.caption - }; - } - - _formatResultToClient(result) { return { - geneId: result.geneId, - name: result.symbol, - species: result.speciesScientificName, - accession_id: result.protAcc, - protGi: result.protGi, - aa: result.protLen, - taxId: result.taxId, - protein: result.title, - domains: (result.domains || []).map(d => ({ - id: d.pssmId, - start: d.begin, - end: d.end, - name: d.cddName - })) + id: internalPathways.pathwayId, + name: internalPathways.prettyName || internalPathways.name, + description: internalPathways.pathwayDesc }; } - } diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable_header.tpl.html b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable_header.tpl.html new file mode 100644 index 000000000..7f7c08195 --- /dev/null +++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable_header.tpl.html @@ -0,0 +1,60 @@ +
+
+
+ + + {{ col.displayName }} + + + + + + + + {{col.sort.priority + 1}} + + + +
+
+
diff --git a/client/client/app/components/ngbPathways/ngbPathways.service.js b/client/client/app/components/ngbPathways/ngbPathways.service.js index 1004ccf1f..5572861ca 100644 --- a/client/client/app/components/ngbPathways/ngbPathways.service.js +++ b/client/client/app/components/ngbPathways/ngbPathways.service.js @@ -6,7 +6,7 @@ const PATHWAYS_STATES = { export default class ngbPathwaysService { pathwaysServiceMap = {}; - currentInternalPathwaysId; + currentInternalPathway; constructor(dispatcher, projectContext, ngbInternalPathwaysTableService, ngbInternalPathwaysResultService diff --git a/client/client/app/components/ngbPathways/ngbPathwaysPanel.html b/client/client/app/components/ngbPathways/ngbPathwaysPanel.html index c57b444e4..665618f66 100644 --- a/client/client/app/components/ngbPathways/ngbPathwaysPanel.html +++ b/client/client/app/components/ngbPathways/ngbPathwaysPanel.html @@ -1,17 +1,19 @@
- - - +
+ + + + Search - +
@@ -39,12 +41,12 @@ ng-if="$ctrl.currentPathwaysState === $ctrl.pathwaysStates.KEGG"> + class="blast-search-flex-column" + flex + ng-if="$ctrl.currentPathwaysState === $ctrl.pathwaysStates.INTERNAL_PATHWAYS"> + class="blast-search-flex-column" + flex + ng-if="$ctrl.currentPathwaysState === $ctrl.pathwaysStates.INTERNAL_PATHWAYS_RESULT">
diff --git a/client/client/app/components/ngbPathways/ngbPathwaysPanel.scss b/client/client/app/components/ngbPathways/ngbPathwaysPanel.scss index 9e3695cef..860bddb8d 100644 --- a/client/client/app/components/ngbPathways/ngbPathwaysPanel.scss +++ b/client/client/app/components/ngbPathways/ngbPathwaysPanel.scss @@ -2,11 +2,13 @@ color: rgb(51, 103, 214); font-weight: bold; cursor: pointer; + a { color: inherit; text-decoration: none; } } + .pathways-search-result { padding: 5px 2px; @@ -17,6 +19,32 @@ font-size: 18px; } } + .pathways-no-feature { font-weight: bold; } + +.pathways-search-container { + width: 100%; + display: flex; + margin-top: 10px; + + .pathways-search-input { + font-size: 14px; + margin: 5px 0 10px 6px; + + .pathways-search-input-label { + padding-bottom: 2px; + } + } + .pathways-search-button { + margin: 6px 2px 6px 10px; + line-height: 32px; + min-height: 32px; + height: 32px; + } +} + +.pathways-search-input .md-errors-spacer { + min-height: 0; +} diff --git a/client/client/dataServices/data-service.js b/client/client/dataServices/data-service.js index fc6680b36..67dae878c 100644 --- a/client/client/dataServices/data-service.js +++ b/client/client/dataServices/data-service.js @@ -1,9 +1,6 @@ -import { - SessionExpirationBehavior, - SessionExpirationBehaviorStorageKey -} from './utils/session-expiration-behavior'; import BluebirdPromise from 'bluebird'; import ngbConstants from '../constants'; +import {SessionExpirationBehavior, SessionExpirationBehaviorStorageKey} from './utils/session-expiration-behavior'; const AUTH_ERROR_CODE = 401; const ERROR_CODE_RANGE_START = 400; @@ -101,6 +98,20 @@ export class DataService { }); } + getRawFile(method, url, data, ...rest) { + return $http(method, this._serverUrl + url, data, ...rest) + .then((xhr) => { + if (xhr.status === AUTH_ERROR_CODE) { + this.handleAuthenticationError(); + return Promise.reject(xhr.response); + } + if (xhr.status >= ERROR_CODE_RANGE_START) { + return Promise.reject(xhr.response); + } + return xhr.responseText; + }); + } + getFullUrl(url) { return this._serverUrl + url; } diff --git a/client/client/dataServices/genome/genome-data-service.js b/client/client/dataServices/genome/genome-data-service.js index 50675912c..198101ddc 100644 --- a/client/client/dataServices/genome/genome-data-service.js +++ b/client/client/dataServices/genome/genome-data-service.js @@ -238,14 +238,28 @@ export class GenomeDataService extends DataService { } getInternalPathwaysLoad(filter) { - return this._internalPathways; + // return this._internalPathways; return new Promise((resolve, reject) => { - this.post('homolog/search', filter) + this.post('pathways', filter) .then((data) => { if (data) { resolve(data); } else { - reject(new Error('No orthologs or paralogs received')); + reject(new Error('No pathways received')); + } + }) + .catch(reject); + }); + } + + loadPathwayFileById(id) { + return new Promise((resolve, reject) => { + this.getRawFile('get', `pathway/content/${id}`, null, {customResponseType: 'text'}) + .then((data) => { + if (data) { + resolve(data); + } else { + reject(new Error('No pathway info received')); } }) .catch(reject);