diff --git a/client/client/app/components/ngbGenesTablePanel/ngbGenesTable/ngbGenesTableContextMenu/ngbGenesTableContextMenu.controller.js b/client/client/app/components/ngbGenesTablePanel/ngbGenesTable/ngbGenesTableContextMenu/ngbGenesTableContextMenu.controller.js
index 3872fe001..f5b4d7ed2 100644
--- a/client/client/app/components/ngbGenesTablePanel/ngbGenesTable/ngbGenesTableContextMenu/ngbGenesTableContextMenu.controller.js
+++ b/client/client/app/components/ngbGenesTablePanel/ngbGenesTable/ngbGenesTableContextMenu/ngbGenesTableContextMenu.controller.js
@@ -126,7 +126,9 @@ export default class NgbGenesTableContextMenuController extends BaseController {
layoutChange.displayed = true;
this.dispatcher.emitSimpleEvent('layout:item:change', {layoutChange});
const readInfo = {
- search: this.entity[`${this.ngbGenesTableService.defaultPrefix}featureName`]
+ search: this.entity[`${this.ngbGenesTableService.defaultPrefix}featureName`],
+ speciesList: [],
+ rewriteSpecies: true
};
const data = {
...readInfo,
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/index.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/index.js
index f2accbf01..48fb90547 100644
--- a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/index.js
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/index.js
@@ -3,10 +3,13 @@ import angular from 'angular';
import component from './ngbInternalPathwaysTable.component';
import controller from './ngbInternalPathwaysTable.controller';
import './ngbInternalPathwaysTable.scss';
+
import service from './ngbInternalPathwaysTable.service';
+import ngbInternalPathwaysTableFilter from './ngbInternalPathwaysTableFilter';
+
export default angular
- .module('ngbInternalPathwaysTable', [])
+ .module('ngbInternalPathwaysTable', [ngbInternalPathwaysTableFilter])
.service('ngbInternalPathwaysTableService', service.instance)
.controller(controller.UID, controller)
.component('ngbInternalPathwaysTable', component)
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.controller.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.controller.js
index 7bb12bc2a..2c846d2b1 100644
--- a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.controller.js
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.controller.js
@@ -7,6 +7,7 @@ const RESIZE_DELAY = 300;
export default class ngbInternalPathwaysTableController extends baseController {
dispatcher;
isProgressShown = true;
+ displayInternalPathwaysFilter = true;
errorMessageList = [];
debounce = (new Debounce()).debounce;
gridOptions = {
@@ -39,7 +40,9 @@ export default class ngbInternalPathwaysTableController extends baseController {
events = {
'pathways:internalPathways:page:change': this.loadData.bind(this),
'pathways:internalPathways:search': this.initialize.bind(this),
- 'read:show:pathways': this.loadData.bind(this)
+ 'pathways:internalPathways:species:loaded': this.initialize.bind(this),
+ 'read:show:pathways': this.loadData.bind(this),
+ 'pathways:internalPathways:refresh': this.loadData.bind(this),
};
constructor($scope, $timeout, dispatcher,
@@ -55,6 +58,7 @@ export default class ngbInternalPathwaysTableController extends baseController {
uiGridConstants,
});
+ this.displayInternalPathwaysFilter = this.ngbInternalPathwaysTableService.displayInternalPathwaysFilter;
this.initEvents();
}
@@ -85,7 +89,9 @@ export default class ngbInternalPathwaysTableController extends baseController {
});
}
});
- await this.loadData();
+ if (this.ngbInternalPathwaysTableService.isInitialized) {
+ await this.loadData();
+ }
this.isProgressShown = false;
}
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.service.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.service.js
index d52ff8beb..a1c66b2e0 100644
--- a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.service.js
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable.service.js
@@ -1,17 +1,19 @@
import ClientPaginationService from '../../../shared/services/clientPaginationService';
const DEFAULT_INTERNAL_PATHWAYS_COLUMNS = [
- 'name', 'description', 'source'
+ 'name', 'description', 'source', 'organisms'
];
const DEFAULT_ORDERBY_INTERNAL_PATHWAYS_COLUMNS = {
'name': 'name',
'description': 'description',
- 'source': 'source'
+ 'source': 'source',
+ 'organisms': 'organisms'
};
const INTERNAL_PATHWAYS_COLUMN_TITLES = {
name: 'Map',
description: 'Description',
- source: 'Source'
+ source: 'Source',
+ organisms: 'Species'
};
const DATABASE_SOURCES = {
CUSTOM: 'Custom',
@@ -20,12 +22,16 @@ const DATABASE_SOURCES = {
};
const FIRST_PAGE = 1;
const PAGE_SIZE = 11;
+const blockFilterInternalPathwaysTimeout = 500;
export default class ngbInternalPathwaysTableService extends ClientPaginationService {
+ _blockFilterInternalPathways;
+
constructor(dispatcher, genomeDataService) {
super(dispatcher, FIRST_PAGE, PAGE_SIZE, 'pathways:internalPathways:page:change');
this.dispatcher = dispatcher;
this.genomeDataService = genomeDataService;
+ this.loadSpeciesList();
}
_internalPathways;
@@ -40,6 +46,12 @@ export default class ngbInternalPathwaysTableService extends ClientPaginationSer
return this._pageError;
}
+ _isInitialized = false;
+
+ get isInitialized() {
+ return this._isInitialized;
+ }
+
get columnTitleMap() {
return INTERNAL_PATHWAYS_COLUMN_TITLES;
}
@@ -48,35 +60,75 @@ export default class ngbInternalPathwaysTableService extends ClientPaginationSer
return DEFAULT_ORDERBY_INTERNAL_PATHWAYS_COLUMNS;
}
+ _internalPathwaysFilter = {};
+
+ get internalPathwaysFilter() {
+ return this._internalPathwaysFilter;
+ }
+
get internalPathwaysColumns() {
- if (!localStorage.getItem('internalPathwaysColumnNames')) {
- localStorage.setItem('internalPathwaysColumnNames', JSON.stringify(DEFAULT_INTERNAL_PATHWAYS_COLUMNS));
+ if (!localStorage.getItem('internalPathwaysColumns')) {
+ localStorage.setItem('internalPathwaysColumns', JSON.stringify(DEFAULT_INTERNAL_PATHWAYS_COLUMNS));
}
- return JSON.parse(localStorage.getItem('internalPathwaysColumnNames'));
+ return JSON.parse(localStorage.getItem('internalPathwaysColumns'));
}
set internalPathwaysColumns(columns) {
- localStorage.setItem('internalPathwaysColumnNames', JSON.stringify(columns || []));
+ localStorage.setItem('internalPathwaysColumns', JSON.stringify(columns || []));
+ }
+
+ _displayInternalPathwaysFilter = true;
+
+ get displayInternalPathwaysFilter() {
+ if (this._displayInternalPathwaysFilter !== undefined) {
+ return this._displayInternalPathwaysFilter;
+ } else {
+ this._displayInternalPathwaysFilter = JSON.parse(localStorage.getItem('displayInternalPathwaysFilter')) || false;
+ return this._displayInternalPathwaysFilter;
+ }
+ }
+
+ _speciesList;
+
+ get speciesList() {
+ return this._speciesList || [];
+ }
+
+ set speciesList(value) {
+ this._speciesList = (value || []);
}
static instance(dispatcher, genomeDataService) {
return new ngbInternalPathwaysTableService(dispatcher, genomeDataService);
}
+ async loadSpeciesList() {
+ this.speciesList = await this.genomeDataService.getSpeciesList();
+ this._isInitialized = true;
+ this.dispatcher.emitSimpleEvent('pathways:internalPathways:species:loaded');
+ }
+
async searchInternalPathways(currentSearch) {
this._internalPathways = await this.loadInternalPathways(currentSearch);
this.dispatcher.emitSimpleEvent('internalPathways:result:change');
}
async loadInternalPathways(currentSearch) {
+ if (currentSearch.rewriteSpecies) {
+ this.internalPathwaysFilter.organisms = currentSearch.speciesList;
+ currentSearch.speciesList = [];
+ currentSearch.rewriteSpecies = false;
+ }
const filter = {
pagingInfo: {
pageSize: this.pageSize,
pageNum: this.currentPage
},
sortInfo: this.orderBy ? this.orderBy[0] : null,
- term: currentSearch
+ term: currentSearch.search || '',
+ taxIds: this.internalPathwaysFilter.organisms || []
};
+
const data = await this.genomeDataService.getInternalPathwaysLoad(filter);
if (data.error) {
this.totalPages = 0;
@@ -125,6 +177,27 @@ export default class ngbInternalPathwaysTableService extends ClientPaginationSer
};
break;
}
+ case 'organisms': {
+ columnSettings = {
+ cellTemplate: `
{{row.entity.organismsViewValue}}
`,
+ enableHiding: false,
+ enableSorting: true,
+ enableFiltering: true,
+ field: 'organisms',
+ headerCellTemplate: headerCells,
+ name: this.columnTitleMap[column],
+ filterApplied: () => this.internalPathwaysFieldIsFiltered(column),
+ menuItems: [
+ {
+ title: 'Clear column filter',
+ action: () => this.clearInternalPathwaysFieldFilter(column),
+ shown: () => this.internalPathwaysFieldIsFiltered(column)
+ }
+ ],
+ };
+ break;
+ }
default: {
columnSettings = {
enableHiding: false,
@@ -150,8 +223,40 @@ export default class ngbInternalPathwaysTableService extends ClientPaginationSer
return result;
}
+ clearInternalPathwaysFilter() {
+ if (this._blockFilterInternalPathways) {
+ clearTimeout(this._blockFilterInternalPathways);
+ this._blockFilterInternalPathways = null;
+ }
+ this._internalPathwaysFilter = {};
+ this.dispatcher.emit('pathways:internalPathways:refresh');
+ this._blockFilterInternalPathways = setTimeout(() => {
+ this._blockFilterInternalPathways = null;
+ }, blockFilterInternalPathwaysTimeout);
+ }
+
+ internalPathwaysFieldIsFiltered(fieldName) {
+ return this.internalPathwaysFilter[fieldName] !== undefined;
+ }
+
+ clearInternalPathwaysFieldFilter(fieldName) {
+ this.internalPathwaysFilter[fieldName] = undefined;
+ this.dispatcher.emit('pathways:internalPathways:refresh');
+ }
+
+ canScheduleFilterInternalPathways() {
+ return !this._blockFilterInternalPathways;
+ }
+
+ scheduleFilterInternalPathways() {
+ if (this._blockFilterInternalPathways) {
+ return;
+ }
+ this.dispatcher.emit('pathways:internalPathways:refresh');
+ }
+
_formatServerToClient(internalPathways) {
- return {
+ const result = {
id: internalPathways.pathwayId,
name: internalPathways.prettyName || internalPathways.name,
description: internalPathways.pathwayDesc,
@@ -159,5 +264,11 @@ export default class ngbInternalPathwaysTableService extends ClientPaginationSer
source: DATABASE_SOURCES[internalPathways.databaseSource] || internalPathways.databaseSource,
organisms: internalPathways.organisms
};
+ if (internalPathways.organisms) {
+ result.organismsViewValue = internalPathways.organisms
+ .map(organism => organism.speciesName || organism.taxId)
+ .join(', ');
+ }
+ return result;
}
}
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/index.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/index.js
new file mode 100644
index 000000000..92ecf7cfa
--- /dev/null
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/index.js
@@ -0,0 +1,13 @@
+import angular from 'angular';
+import filterList from './ngbInternalPathwaysFilterList';
+
+// Import internal modules
+import component from './ngbInternalPathwaysTableFilter.component';
+import controller from './ngbInternalPathwaysTableFilter.controller';
+import './ngbInternalPathwaysTableFilter.scss';
+
+// Import external modules
+export default angular.module('ngbInternalPathwaysTableFilter', [filterList])
+ .controller(controller.UID, controller)
+ .component('ngbInternalPathwaysTableFilter', component)
+ .name;
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/index.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/index.js
new file mode 100644
index 000000000..35c08a03b
--- /dev/null
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/index.js
@@ -0,0 +1,14 @@
+import angular from 'angular';
+import scroller from '../../../../../shared/filter/filterList/ngbFilterList.scroller';
+
+// Import internal modules
+import component from './ngbInternalPathwaysFilterList.component';
+import controller from './ngbInternalPathwaysFilterList.controller';
+import './ngbInternalPathwaysFilterList.scss';
+
+// Import external modules
+export default angular.module('ngbInternalPathwaysFilterList', [])
+ .directive('preventParentScroll', scroller)
+ .controller(controller.UID, controller)
+ .component('ngbInternalPathwaysFilterList', component)
+ .name;
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
new file mode 100644
index 000000000..cf32f910a
--- /dev/null
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbFilterList.elements.js
@@ -0,0 +1,153 @@
+const MAX_ITEMS_TO_DISPLAY = 100;
+const Math = window.Math;
+
+export default class ListElements {
+
+ listFn;
+ onSearchStartCallback;
+ onSearchFinishedCallback;
+ preLoadedList = {
+ model: [],
+ view: []
+ };
+ fullList = null;
+ token;
+
+ constructor(listFn, callbacks) {
+ this.listFn = listFn;
+ let list;
+ if (listFn instanceof Array) {
+ list = listFn;
+ this.listFn = (searchCriteria) => {
+ if (!searchCriteria || !searchCriteria.length) {
+ return {
+ model: list,
+ view: list
+ };
+ }
+ const filteredList = list.filter(item => item.toLowerCase().indexOf(searchCriteria.toLowerCase()) === 0);
+ return {
+ model: filteredList,
+ view: filteredList
+ };
+ };
+ } else if(listFn.hasOwnProperty('model')) {
+ list = {
+ model: listFn.model
+ };
+ if (listFn.hasOwnProperty('view')) {
+ list.view = listFn.view;
+ } else {
+ list.view = listFn.model;
+ }
+ this.listFn = (searchCriteria) => {
+ if (!searchCriteria || !searchCriteria.length) {
+ return {
+ model: list,
+ view: list
+ };
+ }
+ const result = {
+ model: [],
+ view: []
+ };
+ list.model.forEach((item, index) => {
+ if (item.toLowerCase().indexOf(searchCriteria.toLowerCase()) === 0) {
+ result.model.push(item);
+ result.view.push(list.view[index]);
+ }
+ });
+ return result;
+ };
+ }
+ const {onSearchStartCallback, onSearchFinishedCallback} = callbacks;
+ this.onSearchStartCallback = onSearchStartCallback;
+ this.onSearchFinishedCallback = onSearchFinishedCallback;
+ this.refreshList();
+ }
+
+ _isLoading = false;
+
+ get isLoading() {
+ return this._isLoading;
+ }
+
+ refreshList(searchString) {
+ this._isLoading = true;
+ const token = this.token = {};
+ if (this.onSearchStartCallback) {
+ this.onSearchStartCallback(searchString);
+ }
+ (async() => {
+ let items;
+ let shouldUpdateScope = true;
+ if ((!searchString || !searchString.length) && this.fullList) {
+ items = this.fullList;
+ shouldUpdateScope = false;
+ } else {
+ if (!this.fullList || this.fullList.model.length === 0) {
+ 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
+ };
+ shouldUpdateScope = false;
+ } else {
+ items = await this.listFn(searchString);
+ shouldUpdateScope = true;
+ }
+ } else {
+ items = this.fullList;
+ shouldUpdateScope = false;
+ }
+ if (!searchString || !searchString.length) {
+ this.fullList = items;
+ }
+ }
+ if (token === this.token) {
+ this.token = null;
+ this._isLoading = false;
+ this.preLoadedList = {
+ model: [],
+ view: []
+ };
+ if (items.model.length < MAX_ITEMS_TO_DISPLAY) {
+ this.preLoadedList.model = items.model;
+ this.preLoadedList.view = items.view;
+ } else {
+ this.preLoadedList = {
+ model: [{
+ placeholder: true,
+ message: `Too much results (${items.model.length}). Top ${MAX_ITEMS_TO_DISPLAY} are shown`
+ }],
+ view: [{placeholder: true}]
+ };
+ this.preLoadedList.model.push({divider: true});
+ this.preLoadedList.view.push({divider: true});
+ for (let i = 0; i < Math.min(items.model.length, MAX_ITEMS_TO_DISPLAY); i++) {
+ this.preLoadedList.model.push(items.model[i]);
+ this.preLoadedList.view.push(items.view[i]);
+ }
+ }
+ if (this.onSearchFinishedCallback) {
+ this.onSearchFinishedCallback(searchString, shouldUpdateScope);
+ }
+ }
+ })();
+ }
+
+ getItemAtIndex(index) {
+ if (index >= this.preLoadedList.model.length) {
+ return null;
+ }
+ return this.preLoadedList.model[index];
+ }
+
+ getLength() {
+ return this.preLoadedList.model.length;
+ }
+
+}
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.component.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.component.js
new file mode 100644
index 000000000..1e3878712
--- /dev/null
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.component.js
@@ -0,0 +1,10 @@
+import controller from './ngbInternalPathwaysFilterList.controller';
+
+export default {
+ bindings: {
+ list: '<',
+ field: '<'
+ },
+ controller: controller.UID,
+ template: require('./ngbInternalPathwaysFilterList.tpl.html')
+};
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
new file mode 100644
index 000000000..a5d8469bf
--- /dev/null
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.controller.js
@@ -0,0 +1,161 @@
+import ListElements from './ngbFilterList.elements';
+
+export default class ngbInternalPathwaysFilterListController {
+ listIsDisplayed = false;
+ hideListTimeout = null;
+ scope;
+ input;
+ selectedItems = [];
+ displayText = '';
+ listElements = null;
+ _hideListIsPrevented = false;
+
+ constructor($scope, $element, ngbInternalPathwaysTableService) {
+ this.scope = $scope;
+ this.ngbInternalPathwaysTableService = ngbInternalPathwaysTableService;
+ this.input = $element.find('.ngb-filter-input')[0];
+ this.listElements = new ListElements(this.list, {
+ onSearchFinishedCallback: this.searchFinished.bind(this)
+ });
+ this.scope.$watch('$ctrl.list', () => {
+ this.listElements = new ListElements(this.list, {
+ onSearchFinishedCallback: this.searchFinished.bind(this)
+ });
+ });
+ switch (this.field.field) {
+ 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(', ');
+ }
+ break;
+ }
+ }
+ }
+
+ static get UID() {
+ return 'ngbInternalPathwaysFilterListController';
+ }
+
+ searchFinished(searchString, shouldUpdateScope) {
+ const parts = this.displayText.split(',').map(part => part.trim().toLowerCase());
+ let last = '';
+ if (parts.length) {
+ 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 (shouldUpdateScope) {
+ this.scope.$apply();
+ }
+ }
+
+ displayList() {
+ if (this.hideListTimeout) {
+ clearTimeout(this.hideListTimeout);
+ this.hideListTimeout = null;
+ }
+ this.listIsDisplayed = true;
+ }
+
+ preventListFromClosing() {
+ this._hideListIsPrevented = true;
+ this.input.focus();
+ }
+
+ stopPreventListFromClosing() {
+ this._hideListIsPrevented = false;
+ this.input.focus();
+ }
+
+ hideList() {
+ if (this.hideListTimeout) {
+ clearTimeout(this.hideListTimeout);
+ this.hideListTimeout = null;
+ }
+ if (this._hideListIsPrevented) {
+ return;
+ }
+ this.listIsDisplayed = false;
+ this.apply();
+ this.scope.$apply();
+ }
+
+ hideListDelayed() {
+ if (this.hideListTimeout) {
+ clearTimeout(this.hideListTimeout);
+ this.hideListTimeout = null;
+ }
+ this.hideListTimeout = setTimeout(::this.hideList, 100);
+ }
+
+ itemIsSelected(item) {
+ return this.selectedItems.filter(listItem => listItem.toLowerCase() === item.toLowerCase()).length > 0;
+ }
+
+ inputChanged() {
+ const textParts = (this.displayText || '').split(',');
+ const lastPart = textParts[textParts.length - 1].trim().toLowerCase();
+ this.listElements.refreshList(lastPart);
+ }
+
+ didClickOnItem(item) {
+ if (this.hideListTimeout) {
+ clearTimeout(this.hideListTimeout);
+ this.hideListTimeout = null;
+ }
+ this.input.focus();
+ const index = this.selectedItems.indexOf(item);
+ if (index >= 0) {
+ this.selectedItems.splice(index, 1);
+ } else {
+ this.selectedItems.push(item);
+ }
+ if (this.selectedItems.length) {
+ this.displayText = [...this.selectedItems, ''].join(', ');
+ } else {
+ this.displayText = '';
+ }
+ this.listElements.refreshList(null);
+ }
+
+ 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);
+ } else {
+ this.selectedItems = parts.filter(part => part !== '');
+ }
+ this.displayText = this.selectedItems.join(', ');
+ this.listIsDisplayed = false;
+ if (!this.ngbInternalPathwaysTableService.canScheduleFilterInternalPathways()) {
+ return;
+ }
+ switch (this.field.field) {
+ case 'organisms': {
+ const selectedItemsLowerCase = this.selectedItems.map(i => i.toLowerCase());
+ const prevValue = (this.ngbInternalPathwaysTableService.internalPathwaysFilter.organisms || []);
+ prevValue.sort();
+ const prevValueStr = JSON.stringify(prevValue).toUpperCase();
+ const currValue = this.ngbInternalPathwaysTableService.speciesList
+ .filter(organism => selectedItemsLowerCase.indexOf(organism.taxId.toString()) >= 0)
+ .map(organism => organism.taxId);
+ currValue.sort();
+ const currValueStr = JSON.stringify(currValue).toUpperCase();
+ if (currValueStr !== prevValueStr) {
+ this.ngbInternalPathwaysTableService.internalPathwaysFilter.organisms = currValue;
+ this.ngbInternalPathwaysTableService.scheduleFilterInternalPathways();
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.scss b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.scss
new file mode 100644
index 000000000..8ad6ae33d
--- /dev/null
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.scss
@@ -0,0 +1,28 @@
+ngb-variants-filter-list {
+ md-select {
+ margin: 0;
+ padding: 0;
+ }
+}
+
+.ngb-filter-list-container {
+ background-color: #ffffff;
+ position: fixed;
+ width: 200px;
+ max-height: 300px;
+ overflow-y: scroll;
+ z-index: 10;
+ .ngb-filter-list-item {
+ min-height: 20px;
+ padding: 3px;
+ .ngb-filter-list-item-placeholder {
+ font-style: italic;
+ }
+ }
+ .ngb-filter-list-loading {
+ padding: 10px;
+ }
+}
+.ngb-filter-list-container-wide {
+ width: 400px;
+}
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
new file mode 100644
index 000000000..912c76668
--- /dev/null
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysFilterList/ngbInternalPathwaysFilterList.tpl.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+ {{item.message}}
+
+
+
+
+
+
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.component.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.component.js
new file mode 100644
index 000000000..fc3c0346b
--- /dev/null
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.component.js
@@ -0,0 +1,9 @@
+import controller from './ngbInternalPathwaysTableFilter.controller';
+
+export default {
+ bindings: {
+ column: '<'
+ },
+ controller: controller.UID,
+ template: require('./ngbInternalPathwaysTableFilter.tpl.html')
+};
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.controller.js b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.controller.js
new file mode 100644
index 000000000..0156313dd
--- /dev/null
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.controller.js
@@ -0,0 +1,25 @@
+export default class ngbInternalPathwaysTableFilterController {
+
+ isRange = false;
+ isString = false;
+ isList = false;
+
+ constructor(ngbInternalPathwaysTableService) {
+ switch (this.column.field) {
+ case 'organisms': {
+ this.isList = true;
+ this.list = async () => new Promise((resolve) => {
+ resolve({
+ model: ngbInternalPathwaysTableService.speciesList.map(e => e.taxId.toString()),
+ view: ngbInternalPathwaysTableService.speciesList
+ });
+ });
+ break;
+ }
+ }
+ }
+
+ static get UID() {
+ return 'ngbInternalPathwaysTableFilterController';
+ }
+}
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.scss b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.scss
new file mode 100644
index 000000000..4e659fb36
--- /dev/null
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.scss
@@ -0,0 +1,7 @@
+ngb-internal-pathways-table-filter {
+ padding-left: 1px;
+ padding-right: 3px;
+ input.ngb-filter-input {
+ height: 14px;
+ }
+}
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.tpl.html b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.tpl.html
new file mode 100644
index 000000000..84d74184e
--- /dev/null
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTableFilter/ngbInternalPathwaysTableFilter.tpl.html
@@ -0,0 +1,5 @@
+
+
+
diff --git a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable_header.tpl.html b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable_header.tpl.html
index 7f7c08195..b6f450a87 100644
--- a/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable_header.tpl.html
+++ b/client/client/app/components/ngbPathways/ngbInternalPathwaysTable/ngbInternalPathwaysTable_header.tpl.html
@@ -57,4 +57,5 @@
+
diff --git a/client/client/app/components/ngbPathways/ngbPathways.service.js b/client/client/app/components/ngbPathways/ngbPathways.service.js
index 1ff91be25..15a4dc889 100644
--- a/client/client/app/components/ngbPathways/ngbPathways.service.js
+++ b/client/client/app/components/ngbPathways/ngbPathways.service.js
@@ -82,7 +82,7 @@ export default class ngbPathwaysService {
initEvents() {
this.dispatcher.on('read:show:pathways', data => {
- this.currentSearch = data ? data.search : null;
+ this.currentSearch = data || null;
});
}
diff --git a/client/client/app/components/ngbPathways/ngbPathwaysAnnotationDlg/ngbPathwaysAnnotationAddDlg.controller.js b/client/client/app/components/ngbPathways/ngbPathwaysAnnotationDlg/ngbPathwaysAnnotationAddDlg.controller.js
index 8a659c749..cdaacdee6 100644
--- a/client/client/app/components/ngbPathways/ngbPathwaysAnnotationDlg/ngbPathwaysAnnotationAddDlg.controller.js
+++ b/client/client/app/components/ngbPathways/ngbPathwaysAnnotationDlg/ngbPathwaysAnnotationAddDlg.controller.js
@@ -26,7 +26,7 @@ export default class ngbPathwaysAnnotationAddDlgController {
}
get isStateValid() {
- return this.annotation.type !== undefined
+ return this.annotation.type !== undefined && this.annotation.type !== null
&& (this.annotation.type === this.ngbPathwaysAnnotationService.annotationTypeList.MANUAL
|| this.annotation.header !== undefined);
}
diff --git a/client/client/app/components/ngbPathways/ngbPathwaysPanel.controller.js b/client/client/app/components/ngbPathways/ngbPathwaysPanel.controller.js
index 97f56637c..960fdd36b 100644
--- a/client/client/app/components/ngbPathways/ngbPathwaysPanel.controller.js
+++ b/client/client/app/components/ngbPathways/ngbPathwaysPanel.controller.js
@@ -25,6 +25,7 @@ export default class ngbPathwaysPanelController extends baseController {
this.pathwaysStates = this.ngbPathwaysService.pathwaysStates;
this.initEvents();
this.changeState(this.ngbPathwaysService.currentState);
+ this.searchPathway();
}
static get UID() {
@@ -48,7 +49,11 @@ export default class ngbPathwaysPanelController extends baseController {
}
searchPathway() {
- this.ngbPathwaysService.currentSearch = this.searchRequest;
+ this.ngbPathwaysService.currentSearch = {
+ search: this.searchRequest,
+ speciesList: [],
+ rewriteSpecies: true
+ };
this.dispatcher.emitSimpleEvent('pathways:internalPathways:search');
this.changeState('INTERNAL_PATHWAYS');
}
diff --git a/client/client/app/components/ngbPathways/ngbPathwaysPanel.html b/client/client/app/components/ngbPathways/ngbPathwaysPanel.html
index 0cb9a315a..c62c485d0 100644
--- a/client/client/app/components/ngbPathways/ngbPathwaysPanel.html
+++ b/client/client/app/components/ngbPathways/ngbPathwaysPanel.html
@@ -10,7 +10,6 @@
Search
diff --git a/client/client/app/components/ngbTracksView/ngbTrack/ngbTrack.events.js b/client/client/app/components/ngbTracksView/ngbTrack/ngbTrack.events.js
index fd7bf4eed..f3d80b3f2 100644
--- a/client/client/app/components/ngbTracksView/ngbTrack/ngbTrack.events.js
+++ b/client/client/app/components/ngbTracksView/ngbTrack/ngbTrack.events.js
@@ -220,6 +220,10 @@ export default class ngbTrackEvents {
if (data.feature.feature && data.feature.name) {
const layoutChange = this.appLayout.Panels.pathways;
layoutChange.displayed = true;
+ const [reference] = this.projectContext.references.filter(ref => ref.id === track.referenceId);
+ const speciesList = reference && reference.species
+ ? [reference.species.taxId]
+ : null;
menuData.push({
events: [
{
@@ -228,7 +232,9 @@ export default class ngbTrackEvents {
},
{
data: {
- search: data.feature.name
+ speciesList,
+ search: data.feature.name,
+ rewriteSpecies: true
},
name: 'read:show:pathways'
}],
diff --git a/client/client/app/components/ngbVariantsTablePanel/ngbVariantsTable/ngbVariantsTable.service.js b/client/client/app/components/ngbVariantsTablePanel/ngbVariantsTable/ngbVariantsTable.service.js
index d6cbecae4..9dc2f0566 100644
--- a/client/client/app/components/ngbVariantsTablePanel/ngbVariantsTable/ngbVariantsTable.service.js
+++ b/client/client/app/components/ngbVariantsTablePanel/ngbVariantsTable/ngbVariantsTable.service.js
@@ -1,5 +1,3 @@
-import headerCells from './ngbVariantsTable_header.tpl.html';
-
export default class ngbVariantsTableService {
static instance(projectContext, genomeDataService, projectDataService, variantsTableMessages, uiGridConstants) {
@@ -115,7 +113,7 @@ export default class ngbVariantsTableService {
break;
case 'sampleNames': {
columnSettings = {
- cellTemplate: `{{COL_FIELD | array}}
`,
+ cellTemplate: '{{COL_FIELD | array}}
',
enableHiding: false,
field: 'sampleNames',
headerCellTemplate: headerCells,
diff --git a/client/client/dataServices/genome/genome-data-service.js b/client/client/dataServices/genome/genome-data-service.js
index 198101ddc..db5364312 100644
--- a/client/client/dataServices/genome/genome-data-service.js
+++ b/client/client/dataServices/genome/genome-data-service.js
@@ -237,6 +237,20 @@ export class GenomeDataService extends DataService {
});
}
+ getSpeciesList() {
+ return new Promise((resolve, reject) => {
+ this.get('pathway/species')
+ .then((data) => {
+ if (data) {
+ resolve(data);
+ } else {
+ resolve([]);
+ }
+ })
+ .catch(reject);
+ });
+ }
+
getInternalPathwaysLoad(filter) {
// return this._internalPathways;
return new Promise((resolve, reject) => {