From be3b09d0339d681b72dea26a5aac545724daa188 Mon Sep 17 00:00:00 2001 From: Dmitrii Krasnov Date: Thu, 7 Apr 2022 16:59:18 +0500 Subject: [PATCH] Metabolic pathways visualisation (#731): display species name in table filter is applicable --- .../ngbFilterList.elements.js | 14 +++- ...gbInternalPathwaysFilterList.controller.js | 83 +++++++++++++++---- .../ngbInternalPathwaysFilterList.tpl.html | 5 +- client/client/app/shared/utils/deepSearch.js | 17 ++++ 4 files changed, 98 insertions(+), 21 deletions(-) create mode 100644 client/client/app/shared/utils/deepSearch.js diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbFilterList.elements.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbFilterList.elements.js index cf32f910a..ea31a882e 100644 --- a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbFilterList.elements.js +++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbFilterList.elements.js @@ -1,3 +1,5 @@ +import {deepSearch} from '../../../../../shared/utils/deepSearch'; + const MAX_ITEMS_TO_DISPLAY = 100; const Math = window.Math; @@ -89,11 +91,17 @@ export default class ListElements { items = await this.listFn(searchString); } else if (searchString && searchString.length > 0) { if (this.fullList && this.fullList.model.length) { - const filteredList = this.fullList.model.filter(i => i.toLowerCase().indexOf(searchString.toLowerCase()) === 0); items = { - model: filteredList, - view: filteredList + model: [], + view: [] }; + this.fullList.model.forEach((model, index) => { + if (model.toLowerCase().indexOf(searchString.toLowerCase()) === 0 + || deepSearch(this.fullList.view[index], searchString.toLowerCase(), [])) { + items.model.push(model); + items.view.push(this.fullList.view[index]); + } + }); shouldUpdateScope = false; } else { items = await this.listFn(searchString); diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.controller.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.controller.js index a5d8469bf..c479641ea 100644 --- a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.controller.js +++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.controller.js @@ -26,9 +26,8 @@ export default class ngbInternalPathwaysFilterListController { case 'organisms': { if (this.ngbInternalPathwaysTableService.internalPathwaysFilter.organisms) { this.selectedItems = this.ngbInternalPathwaysTableService.speciesList - .filter(organism => this.ngbInternalPathwaysTableService.internalPathwaysFilter.organisms.indexOf(organism.taxId) >= 0) - .map(organism => organism.taxId); - this.displayText = [...this.selectedItems].join(', '); + .filter(organism => this.ngbInternalPathwaysTableService.internalPathwaysFilter.organisms.indexOf(organism.taxId) >= 0); + this.displayText = [...this.selectedItems].map(organism => organism.speciesName || organism.taxId).join(', '); } break; } @@ -46,11 +45,30 @@ export default class ngbInternalPathwaysFilterListController { last = parts[parts.length - 1]; parts.splice(parts.length - 1, 1); } - if (this.listElements.fullList && this.listElements.fullList.model.length > 0) { - this.selectedItems = this.listElements.fullList.model.filter(item => parts.indexOf(item.toLowerCase()) >= 0); - const [fullMatch] = this.listElements.fullList.model.filter(item => item.toLowerCase() === last.toLowerCase()); - if (fullMatch) { - this.selectedItems.push(fullMatch); + if (this.listElements.fullList && this.listElements.fullList.view.length > 0) { + switch (this.field.field) { + case 'organisms': { + this.selectedItems = this.listElements.fullList.view + .filter(item => { + if (item.speciesName) { + return parts.indexOf(item.speciesName.toLowerCase()) >= 0; + } else { + return parts.indexOf(item.taxId) >= 0; + } + }); + const [fullMatch] = this.listElements.fullList.view + .filter(item => { + if (item.speciesName) { + return item.speciesName.toLowerCase() === last.toLowerCase() || item.taxId === last.toLowerCase(); + } else { + return item.taxId === last.toLowerCase(); + } + }); + if (fullMatch) { + this.selectedItems.push(fullMatch); + } + break; + } } } if (shouldUpdateScope) { @@ -98,7 +116,20 @@ export default class ngbInternalPathwaysFilterListController { } itemIsSelected(item) { - return this.selectedItems.filter(listItem => listItem.toLowerCase() === item.toLowerCase()).length > 0; + // TODO: make optional fn to determine display value text and refactor mappedSelectedItems and other dependant entries + let mappedSelectedItems, selectedItem; + switch (this.field.field) { + case 'organisms': { + selectedItem = item.speciesName || item.taxId.toString(); + mappedSelectedItems = this.selectedItems.map(item => item.speciesName || item.taxId); + break; + } + default: { + selectedItem = item; + mappedSelectedItems = this.selectedItems; + } + } + return mappedSelectedItems.filter(listItem => listItem.toLowerCase() === selectedItem.toLowerCase()).length > 0; } inputChanged() { @@ -113,12 +144,25 @@ export default class ngbInternalPathwaysFilterListController { this.hideListTimeout = null; } this.input.focus(); - const index = this.selectedItems.indexOf(item); + let mappedSelectedItems, selectedItem; + switch (this.field.field) { + case 'organisms': { + selectedItem = item.speciesName || item.taxId.toString(); + mappedSelectedItems = this.selectedItems.map(item => item.speciesName || item.taxId); + break; + } + default: { + selectedItem = item; + mappedSelectedItems = this.selectedItems; + } + } + const index = mappedSelectedItems.indexOf(selectedItem); if (index >= 0) { - this.selectedItems.splice(index, 1); + mappedSelectedItems.splice(index, 1); } else { - this.selectedItems.push(item); + mappedSelectedItems.push(selectedItem); } + this.selectedItems = mappedSelectedItems; if (this.selectedItems.length) { this.displayText = [...this.selectedItems, ''].join(', '); } else { @@ -129,19 +173,26 @@ export default class ngbInternalPathwaysFilterListController { apply() { const parts = this.displayText.split(',').map(part => part.trim().toLowerCase()); - if (this.listElements.fullList && this.listElements.length > 0) { - this.selectedItems = this.listElements.fullList.model.filter(item => parts.indexOf(item.toLowerCase()) >= 0); + if (this.listElements.fullList && this.listElements.fullList.view.length > 0) { + this.selectedItems = this.listElements.fullList.view + .filter(item => { + if (item.speciesName) { + return parts.indexOf(item.speciesName.toLowerCase()) >= 0; + } else { + return parts.indexOf(item.taxId.toLowerCase()) >= 0; + } + }); } else { this.selectedItems = parts.filter(part => part !== ''); } - this.displayText = this.selectedItems.join(', '); + this.displayText = this.selectedItems.map(item => item.speciesName || item.taxId).join(', '); this.listIsDisplayed = false; if (!this.ngbInternalPathwaysTableService.canScheduleFilterInternalPathways()) { return; } switch (this.field.field) { case 'organisms': { - const selectedItemsLowerCase = this.selectedItems.map(i => i.toLowerCase()); + const selectedItemsLowerCase = this.selectedItems.map(i => i.taxId.toString()); const prevValue = (this.ngbInternalPathwaysTableService.internalPathwaysFilter.organisms || []); prevValue.sort(); const prevValueStr = JSON.stringify(prevValue).toUpperCase(); diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.tpl.html b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.tpl.html index 912c76668..bf7645029 100644 --- a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.tpl.html +++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.tpl.html @@ -15,8 +15,9 @@ prevent-parent-scroll>
- {{$ctrl.listElements.preLoadedList.view[index].taxId}} {{$ctrl.listElements.preLoadedList.view[index].speciesName.toUpperCase()}} diff --git a/client/client/app/shared/utils/deepSearch.js b/client/client/app/shared/utils/deepSearch.js new file mode 100644 index 000000000..98dbb693e --- /dev/null +++ b/client/client/app/shared/utils/deepSearch.js @@ -0,0 +1,17 @@ +export function deepSearch(obj, term, fieldsToIgnore = []) { + let result = false; + for (const key in obj) { + if (fieldsToIgnore.indexOf(key) > -1) continue; + if (!obj.hasOwnProperty(key) || !obj[key]) continue; + if (obj[key] instanceof Object || obj[key] instanceof Array) { + result = deepSearch(obj[key], term, fieldsToIgnore); + } else { + result = obj[key].toString().toLocaleLowerCase() + .includes(term.toLocaleLowerCase()); + } + if (result) { + return true; + } + } + return false; +}