From 2b621c1a4a10510e61c38b5f5431103d52296915 Mon Sep 17 00:00:00 2001
From: juanf <juanf>
Date: Fri, 4 Nov 2016 13:09:54 +0000
Subject: [PATCH] SSDM-2597 : Tables with proper Pagination and Server side
 Cache. :-)

SVN: 37260
---
 .../html/js/config/StandardProfile.js         |  22 ++
 .../eln-lims/html/js/server/ServerFacade.js   | 116 +++---
 .../AdvancedSearchController.js               |   6 +-
 .../AdvancedSearch/AdvancedSearchView.js      |   2 +-
 .../js/views/DataGrid/DataGridController.js   |   6 +-
 .../html/js/views/DataGrid/DataGridModel.js   |   6 +-
 .../views/DataGrid/ExperimentDataGridUtil.js  |   2 +-
 .../js/views/DataGrid/SampleDataGridUtil.js   | 332 +++++++++++++-----
 .../html/js/views/Export/ExportTreeView.js    |  10 +-
 .../js/views/SampleForm/widgets/LinksView.js  |  41 +--
 .../SampleForm/widgets/StorageListView.js     |   2 +-
 .../SampleHierarchyTableView.js               |   2 +-
 .../SampleTable/SampleTableController.js      |  60 ++--
 .../js/views/SampleTable/SampleTableModel.js  |   1 -
 .../js/views/SampleTable/SampleTableView.js   |  56 ++-
 .../js/views/SideMenu/SideMenuWidgetView.js   |  10 +-
 .../js/views/TrashManager/TrashManagerView.js |   2 +-
 .../js/views/UserManager/UserManagerView.js   |   2 +-
 .../VocabularyManagerView.js                  |   4 +-
 .../webapps/eln-lims/html/lib/grid/js/Grid.js | 121 ++++---
 20 files changed, 493 insertions(+), 310 deletions(-)

diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/StandardProfile.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/StandardProfile.js
index 9f919f04bf1..73a7fa12bda 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/StandardProfile.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/StandardProfile.js
@@ -10,6 +10,28 @@ $.extend(StandardProfile.prototype, DefaultProfile.prototype, {
 		
 		this.hideCodes = true;
 		
+//
+//		Template to populate multiple storage groups
+//
+//		var getStoragGroupFromTemplate = function(groupNumber) {
+//			return {
+//				"STORAGE_PROPERTY_GROUP" : "Physical Storage " + groupNumber, //Where the storage will be painted.
+//				"STORAGE_GROUP_DISPLAY_NAME" : "Physical Storage " + groupNumber, //Storage Group Name
+//				"NAME_PROPERTY" : 		"STORAGE_NAME_" + groupNumber, //Should be a Vocabulary.
+//				"ROW_PROPERTY" : 		"STORAGE_ROW_" + groupNumber, //Should be an integer.
+//				"COLUMN_PROPERTY" : 	"STORAGE_COLUMN_" + groupNumber,  //Should be an integer.
+//				"BOX_PROPERTY" : 		"STORAGE_BOX_NAME_" + groupNumber, //Should be text.
+//				"USER_PROPERTY" : 		"STORAGE_USER_" + groupNumber, //Should be text.
+//				"BOX_SIZE_PROPERTY" : 	"STORAGE_BOX_SIZE_" + groupNumber, //Should be Vocabulary.
+//				"POSITION_PROPERTY" : 	"STORAGE_BOX_POSITION_" + groupNumber //Should be text.
+//			};
+//		}
+//		
+//		var numberOfStorageGroups = 65;
+//		for(var sIdx = 1; sIdx <= numberOfStorageGroups; sIdx++) {
+//			this.storagesConfiguration["STORAGE_PROPERTIES"].push(getStoragGroupFromTemplate(sIdx));
+//		}
+		
 		this.storagesConfiguration = {
 				"isEnabled" : true,
 				"storageSpaceLowWarning" : 0.8, //Storage goes over 80%
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/server/ServerFacade.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/server/ServerFacade.js
index 95a1be54994..1a28646dc6a 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/server/ServerFacade.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/server/ServerFacade.js
@@ -667,47 +667,47 @@ function ServerFacade(openbisServer) {
 	// New Advanced Search
 	//
 	
-	this.searchForDataSetsAdvanced = function(advancedSearchCriteria, callback) {
+	this.searchForDataSetsAdvanced = function(advancedSearchCriteria, advancedFetchOptions, callback) {
 		var criteriaClass = 'as/dto/dataset/search/DataSetSearchCriteria';
 		var fetchOptionsClass = 'as/dto/dataset/fetchoptions/DataSetFetchOptions';
 		var searchMethodName = 'searchDataSets';
-		this.searchForEntityAdvanced(advancedSearchCriteria, callback, criteriaClass, fetchOptionsClass, searchMethodName);
+		this.searchForEntityAdvanced(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass, searchMethodName);
 	}
 	
-	this.searchForExperimentsAdvanced = function(advancedSearchCriteria, callback) {
+	this.searchForExperimentsAdvanced = function(advancedSearchCriteria, advancedFetchOptions, callback) {
 		var criteriaClass = 'as/dto/experiment/search/ExperimentSearchCriteria';
 		var fetchOptionsClass = 'as/dto/experiment/fetchoptions/ExperimentFetchOptions';
 		var searchMethodName = 'searchExperiments';
-		this.searchForEntityAdvanced(advancedSearchCriteria, callback, criteriaClass, fetchOptionsClass, searchMethodName);
+		this.searchForEntityAdvanced(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass, searchMethodName);
 	}
 	
-	this.searchForSamplesAdvanced = function(advancedSearchCriteria, callback) {
+	this.searchForSamplesAdvanced = function(advancedSearchCriteria, advancedFetchOptions, callback) {
 		var criteriaClass = 'as/dto/sample/search/SampleSearchCriteria';
 		var fetchOptionsClass = 'as/dto/sample/fetchoptions/SampleFetchOptions';
 		var searchMethodName = 'searchSamples';
-		this.searchForEntityAdvanced(advancedSearchCriteria, callback, criteriaClass, fetchOptionsClass, searchMethodName);
+		this.searchForEntityAdvanced(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass, searchMethodName);
 	}
 	
-	this.searchForSpacesAdvanced = function(advancedSearchCriteria, callback) {
+	this.searchForSpacesAdvanced = function(advancedSearchCriteria, advancedFetchOptions, callback) {
 		var criteriaClass = 'as/dto/space/search/SpaceSearchCriteria';
 		var fetchOptionsClass = 'as/dto/space/fetchoptions/SpaceFetchOptions';
 		var searchMethodName = 'searchSpaces';
-		this.searchForEntityAdvanced(advancedSearchCriteria, callback, criteriaClass, fetchOptionsClass, searchMethodName);
+		this.searchForEntityAdvanced(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass, searchMethodName);
 	}
 	
-	this.searchForProjectsAdvanced = function(advancedSearchCriteria, callback) {
+	this.searchForProjectsAdvanced = function(advancedSearchCriteria, advancedFetchOptions, callback) {
 		var criteriaClass = 'as/dto/project/search/ProjectSearchCriteria';
 		var fetchOptionsClass = 'as/dto/project/fetchoptions/ProjectFetchOptions';
 		var searchMethodName = 'searchProjects';
-		this.searchForEntityAdvanced(advancedSearchCriteria, callback, criteriaClass, fetchOptionsClass, searchMethodName);
+		this.searchForEntityAdvanced(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass, searchMethodName);
 	}
 	
-	this.searchForEntityAdvanced = function(advancedSearchCriteria, callback, criteriaClass, fetchOptionsClass, searchMethodName) {
+	this.searchForEntityAdvanced = function(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass, searchMethodName) {
 		require(['openbis', 
 		         criteriaClass,
 		         fetchOptionsClass,
 		         'as/dto/common/search/DateObjectEqualToValue'], function(openbis, EntitySearchCriteria, EntityFetchOptions, DateObjectEqualToValue) {
-			
+		
 			try {
 				//Boilerplate
 				var testProtocol = window.location.protocol;
@@ -722,7 +722,7 @@ function ServerFacade(openbisServer) {
 				
 				//Setting the searchCriteria given the advancedSearchCriteria model
 				var searchCriteria = new EntitySearchCriteria();
-				
+			
 				//Setting the fetchOptions given standard settings
 				var fetchOptions = new EntityFetchOptions();
 				if(fetchOptions.withTags) {
@@ -756,13 +756,41 @@ function ServerFacade(openbisServer) {
 					fetchOptions.withProperties();
 				}
 				
-				//Operator
-				var operator = advancedSearchCriteria.logicalOperator;
-				if (!operator) {
-					operator = "AND";
+				if(advancedFetchOptions && advancedFetchOptions.cache) {
+					fetchOptions.cacheMode(advancedFetchOptions.cache);
+				}
+				
+				if(advancedFetchOptions && 
+						advancedFetchOptions.count != null &&
+						advancedFetchOptions.count != undefined && 
+						advancedFetchOptions.from != null &&
+						advancedFetchOptions.from != undefined) {
+					fetchOptions.from(advancedFetchOptions.from);
+					fetchOptions.count(advancedFetchOptions.count);
+				}
+				
+				if(advancedFetchOptions && advancedFetchOptions.sort) {
+					switch(advancedFetchOptions.sort.type) {
+						case "Attribute":
+							fetchOptions.sortBy()[advancedFetchOptions.sort.name]()[advancedFetchOptions.sort.direction]();
+							break;
+						case "Property":
+							fetchOptions.sortBy().property(advancedFetchOptions.sort.name)[advancedFetchOptions.sort.direction]();
+							break;
+					}
+				}
+				
+				var setOperator = function(criteria, operator) {
+					//Operator
+					if (!operator) {
+						operator = "AND";
+					}
+					criteria.withOperator(operator);
+					return criteria;
 				}
-				searchCriteria.withOperator(operator);
 				
+				searchCriteria = setOperator(searchCriteria, advancedSearchCriteria.logicalOperator);
+			
 				//Rules
 				var ruleKeys = Object.keys(advancedSearchCriteria.rules);
 				for (var idx = 0; idx < ruleKeys.length; idx++)
@@ -771,21 +799,21 @@ function ServerFacade(openbisServer) {
 					var fieldName = advancedSearchCriteria.rules[ruleKeys[idx]].name;
 					var fieldNameType = null;
 					var fieldValue = advancedSearchCriteria.rules[ruleKeys[idx]].value;
-					
+				
 					if(fieldName) {
 						var firstDotIndex = fieldName.indexOf(".");
 						fieldNameType = fieldName.substring(0, firstDotIndex);
 						fieldName = fieldName.substring(firstDotIndex + 1, fieldName.length);
 					}
-					
+				
 					if(!fieldValue) {
 						fieldValue = "*";
 					}
-					
+				
 					var setPropertyCriteria = function(criteria, propertyName, propertyValue) {
-						criteria.withProperty(propertyName).thatEquals(propertyValue);
+						criteria.withProperty(propertyName).thatContains(propertyValue);
 					}
-					
+				
 					var setAttributeCriteria = function(criteria, attributeName, attributeValue) {
 						switch(attributeName) {
 							//Used by all entities
@@ -825,10 +853,10 @@ function ServerFacade(openbisServer) {
 								break;
 						}
 					}
-					
+				
 					switch(fieldType) {
 						case "All":
-							searchCriteria.withAnyField().thatEquals(fieldValue);
+							searchCriteria.withAnyField().thatContains(fieldValue);
 							break;
 						case "Property":
 							setPropertyCriteria(searchCriteria, fieldName, fieldValue);
@@ -839,49 +867,49 @@ function ServerFacade(openbisServer) {
 						case "Sample":
 							switch(fieldNameType) {
 								case "PROP":
-									setPropertyCriteria(searchCriteria.withSample(), fieldName, fieldValue);
+									setPropertyCriteria(setOperator(searchCriteria.withSample(),advancedSearchCriteria.logicalOperator), fieldName, fieldValue);
 									break;
 								case "ATTR":
-									setAttributeCriteria(searchCriteria.withSample(), fieldName, fieldValue);
+									setAttributeCriteria(setOperator(searchCriteria.withSample(),advancedSearchCriteria.logicalOperator), fieldName, fieldValue);
 									break;
 							}
 							break;
 						case "Experiment":
 							switch(fieldNameType) {
 								case "PROP":
-									setPropertyCriteria(searchCriteria.withExperiment(), fieldName, fieldValue);
+									setPropertyCriteria(setOperator(searchCriteria.withExperiment(),advancedSearchCriteria.logicalOperator), fieldName, fieldValue);
 									break;
 								case "ATTR":
-									setAttributeCriteria(searchCriteria.withExperiment(), fieldName, fieldValue);
+									setAttributeCriteria(setOperator(searchCriteria.withExperiment(),advancedSearchCriteria.logicalOperator), fieldName, fieldValue);
 									break;
 							}
 							break;
 						case "Parent":
 							switch(fieldNameType) {
 								case "PROP":
-									setPropertyCriteria(searchCriteria.withParents(), fieldName, fieldValue);
+									setPropertyCriteria(setOperator(searchCriteria.withParents(),advancedSearchCriteria.logicalOperator), fieldName, fieldValue);
 									break;
 								case "ATTR":
-									setAttributeCriteria(searchCriteria.withParents(), fieldName, fieldValue);
+									setAttributeCriteria(setOperator(searchCriteria.withParents(),advancedSearchCriteria.logicalOperator), fieldName, fieldValue);
 									break;
 							}
 							break;
 						case "Children":
 							switch(fieldNameType) {
 								case "PROP":
-									setPropertyCriteria(searchCriteria.withChildren(), fieldName, fieldValue);
+									setPropertyCriteria(setOperator(searchCriteria.withChildren(),advancedSearchCriteria.logicalOperator), fieldName, fieldValue);
 									break;
 								case "ATTR":
-									setAttributeCriteria(searchCriteria.withChildren(), fieldName, fieldValue);
+									setAttributeCriteria(setOperator(searchCriteria.withChildren(),advancedSearchCriteria.logicalOperator), fieldName, fieldValue);
 									break;
 							}
 							break;
 					}
 				}
-				
+			
 				v3Api[searchMethodName](searchCriteria, fetchOptions)
 				.done(function(result) {
-					callback(result);  //this will call the method defined in the AdvancedSearchController which will display the table
+					callback(result);
 				})
 				.fail(function(result) {
 					Util.showError("Call failed to server: " + JSON.stringify(result));
@@ -912,26 +940,26 @@ function ServerFacade(openbisServer) {
 		var v1Sample = {};
 		v1Sample["@type"] = "Sample";
 		v1Sample["@id"] = CONST_UNSUPPORTED_NUMBER;
-		v1Sample["spaceCode"] = v3Sample.space.code;
-		v1Sample["permId"] = v3Sample.permId.permId;
+		v1Sample["spaceCode"] = (v3Sample.space)?v3Sample.space.code:null;
+		v1Sample["permId"] = (v3Sample.permId)?v3Sample.permId.permId:null;
 		v1Sample["code"] = v3Sample.code;
-		v1Sample["identifier"] = v3Sample.identifier.identifier;
+		v1Sample["identifier"] = (v3Sample.identifier)?v3Sample.identifier.identifier:null;
 		v1Sample["experimentIdentifierOrNull"] = (v3Sample.experiment)?v3Sample.experiment.identifier.identifier:null;
-		v1Sample["sampleTypeCode"] = v3Sample.type.code;
+		v1Sample["sampleTypeCode"] = (v3Sample.type)?v3Sample.type.code:null;
 		v1Sample["properties"] = v3Sample.properties;
 		
 		v1Sample["registrationDetails"] = {};
 		v1Sample["registrationDetails"]["@type"] = "EntityRegistrationDetails";
 		v1Sample["registrationDetails"]["@id"] = CONST_UNSUPPORTED_NUMBER;
-		v1Sample["registrationDetails"]["userFirstName"] = v3Sample.registrator.firstName;
-		v1Sample["registrationDetails"]["userLastName"] = v3Sample.registrator.lastName;
-		v1Sample["registrationDetails"]["userEmail"] = v3Sample.registrator.email;
-		v1Sample["registrationDetails"]["userId"] = v3Sample.registrator.userId;
+		v1Sample["registrationDetails"]["userFirstName"] = (v3Sample.registrator)?v3Sample.registrator.firstName:null;
+		v1Sample["registrationDetails"]["userLastName"] = (v3Sample.registrator)?v3Sample.registrator.lastName:null;
+		v1Sample["registrationDetails"]["userEmail"] = (v3Sample.registrator)?v3Sample.registrator.email:null;
+		v1Sample["registrationDetails"]["userId"] = (v3Sample.registrator)?v3Sample.registrator.userId:null;
 		v1Sample["registrationDetails"]["modifierFirstName"]  = (v3Sample.modifier)?v3Sample.modifier.firstName:null;
 		v1Sample["registrationDetails"]["modifierLastName"] = (v3Sample.modifier)?v3Sample.modifier.lastName:null;
 		v1Sample["registrationDetails"]["modifierEmail"] = (v3Sample.modifier)?v3Sample.modifier.email:null;
 		v1Sample["registrationDetails"]["modifierUserId"] = (v3Sample.modifier)?v3Sample.modifier.userId:null;
-		v1Sample["registrationDetails"]["registrationDate"] = v3Sample.registrator.registrationDate;
+		v1Sample["registrationDetails"]["registrationDate"] = (v3Sample.registrator)?v3Sample.registrator.registrationDate:null;
 		v1Sample["registrationDetails"]["modificationDate"] = (v3Sample.modifier)?v3Sample.modifier.registrationDate:null;
 		v1Sample["registrationDetails"]["accessTimestamp"] = CONST_UNSUPPORTED_OBJ;
 		
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchController.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchController.js
index 42af5ba8e50..336b0567e6a 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchController.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchController.js
@@ -45,13 +45,13 @@ function AdvancedSearchController(mainController, forceFreeTextSearch) {
 				mainController.serverFacade.searchGlobally(freeText, callbackFunction);
 				break;
 			case "SAMPLE":
-				mainController.serverFacade.searchForSamplesAdvanced(model, callbackFunction);
+				mainController.serverFacade.searchForSamplesAdvanced(model, null, callbackFunction);
 				break;
 			case "EXPERIMENT":
-				mainController.serverFacade.searchForExperimentsAdvanced(model, callbackFunction);
+				mainController.serverFacade.searchForExperimentsAdvanced(model, null, callbackFunction);
 				break;
 			case "DATASET":
-				mainController.serverFacade.searchForDataSetsAdvanced(model, callbackFunction);
+				mainController.serverFacade.searchForDataSetsAdvanced(model, null, callbackFunction);
 				break;
 		}
 	}
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchView.js
index d18d45ca469..bdcae6853e6 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchView.js
@@ -619,7 +619,7 @@ function AdvancedSearchView(advancedSearchController, advancedSearchModel) {
 				callback(rows);
 			};
 			
-			var dataGrid = new DataGridController("Search Results", columns, getDataRows, null, false, "ADVANCED_SEARCH_OPENBIS_" + this._advancedSearchModel.criteria.entityKind);
+			var dataGrid = new DataGridController("Search Results", columns, [], null, getDataRows, null, false, "ADVANCED_SEARCH_OPENBIS_" + this._advancedSearchModel.criteria.entityKind);
 			return dataGrid;
 	}
 	
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/DataGridController.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/DataGridController.js
index dbecaeda7d9..fbc793df1d3 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/DataGridController.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/DataGridController.js
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-function DataGridController(title, columns, data, rowClickEventHandler, showAllColumns,configKey, isMultiselectable) {
+function DataGridController(title, columnsFirst, columnsLast, columnsDynamicFunc, data, rowClickEventHandler, showAllColumns,configKey, isMultiselectable) {
 	this._grid = null;
 	this._dataGridModel = null;
 	this._dataGridView = null;
@@ -37,7 +37,7 @@ function DataGridController(title, columns, data, rowClickEventHandler, showAllC
 					tableConfig = null;
 				}
 			}
-			_this._grid = new Grid(columns, data, showAllColumns, tableConfig, onColumnsChange, isMultiselectable);
+			_this._grid = new Grid(columnsFirst, columnsLast, columnsDynamicFunc, data, showAllColumns, tableConfig, onColumnsChange, isMultiselectable);
 			if(rowClickEventHandler) {
 				_this._grid.addRowClickListener(rowClickEventHandler);
 			}
@@ -45,7 +45,7 @@ function DataGridController(title, columns, data, rowClickEventHandler, showAllC
 				_this._grid.addExtraOptions(extraOptions);
 			}
 			
-			_this._dataGridModel = new DataGridModel(title, columns, data, rowClickEventHandler, _this._grid.render(), isMultiselectable);
+			_this._dataGridModel = new DataGridModel(title, columnsFirst, columnsLast, columnsDynamicFunc, data, rowClickEventHandler, _this._grid.render(), isMultiselectable);
 			_this._dataGridView = new DataGridView(this, _this._dataGridModel);
 			_this._dataGridView.repaint($container);
 		});	
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/DataGridModel.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/DataGridModel.js
index 15d49195fa6..6b8b929fa97 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/DataGridModel.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/DataGridModel.js
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
-function DataGridModel(title, columns, data, rowClickEventHandler, datagrid, isMultiselectable) {
+function DataGridModel(title, columnsFirst, columnsLast, columnsDynamicFunc, data, rowClickEventHandler, datagrid, isMultiselectable) {
 	this.title = title;
-	this.columns = columns;
+	this.columnsFirst = columnsFirst;
+	this.columnsLast = columnsLast;
+	this.columnsDynamicFunc = columnsDynamicFunc;
 	this.data = data;
 	this.rowClickEventHandler = rowClickEventHandler;
 	this.datagrid = datagrid;
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/ExperimentDataGridUtil.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/ExperimentDataGridUtil.js
index 163d3fb959c..19280e4066a 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/ExperimentDataGridUtil.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/ExperimentDataGridUtil.js
@@ -143,7 +143,7 @@ var ExperimentDataGridUtil = new function() {
 			
 		//Create and return a data grid controller
 		var configKey = "ENTITY_TABLE_"+ typeCode;
-		var dataGridController = new DataGridController(null, columns, getDataList, rowClick, false, configKey);
+		var dataGridController = new DataGridController(null, columns, [], null, getDataList, rowClick, false, configKey);
 		return dataGridController;
 	}
 
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/SampleDataGridUtil.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/SampleDataGridUtil.js
index b179dbe56e9..223b91f9851 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/SampleDataGridUtil.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/DataGrid/SampleDataGridUtil.js
@@ -1,27 +1,14 @@
 var SampleDataGridUtil = new function() {
-	this.getSampleDataGrid = function(mandatoryConfigPostKey, samples, rowClick, customOperations, customColumns, optionalConfigPostKey, isOperationsDisabled, isLinksDisabled, isMultiselectable) {
-		
-		var foundPropertyCodes = {};
-		var foundSampleTypes = {};
-		for(var sIdx = 0; sIdx < samples.length; sIdx++) {
-			var sample = samples[sIdx];
-			if(!foundSampleTypes[sample.sampleTypeCode]) {
-				foundSampleTypes[sample.sampleTypeCode] = true;
-				var propertyCodes = profile.getAllPropertiCodesForTypeCode(sample.sampleTypeCode);
-				for(var pIdx = 0; pIdx < propertyCodes.length; pIdx++) {
-					foundPropertyCodes[propertyCodes[pIdx]] = true;
-				}
-			}
-		}
+	this.getSampleDataGrid = function(mandatoryConfigPostKey, samplesOrCriteria, rowClick, customOperations, customColumns, optionalConfigPostKey, isOperationsDisabled, isLinksDisabled, isMultiselectable) {
 		
 		//Fill Columns model
-		var columns = [];
+		var columnsFirst = [];
 		
-		columns.push({
+		columnsFirst.push({
 			label : 'Identifier',
 			property : 'identifier',
 			isExportable: true,
-			sortable : true,
+			sortable : false,
 			render : function(data) {
 				return (isLinksDisabled)?data.identifier:FormUtil.getFormLink(data.identifier, "Sample", data.permId);
 			},
@@ -36,44 +23,56 @@ var SampleDataGridUtil = new function() {
 			}
 		});
 		
-		if(foundPropertyCodes["NAME"]) {
-			columns.push({
-				label : 'Name',
-				property : 'NAME',
-				isExportable: true,
-				sortable : true,
-				render : function(data) {
-					return (isLinksDisabled)?data.NAME:FormUtil.getFormLink(data.NAME, "Sample", data.permId);
-				}
-			});
-		}
+		columnsFirst.push({
+			label : 'Code',
+			property : 'code',
+			isExportable: false,
+			sortable : true
+		});
+		
+		columnsFirst.push({
+			label : 'Sample Type',
+			property : 'sampleTypeCode',
+			isExportable: true,
+			sortable : false
+		});
+		
+		columnsFirst.push({
+			label : 'Name',
+			property : 'NAME',
+			isExportable: true,
+			sortable : true,
+			render : function(data) {
+				return (isLinksDisabled)?data.NAME:FormUtil.getFormLink(data.NAME, "Sample", data.permId);
+			}
+		});
 		
 		if(customColumns) {
-			columns = columns.concat(customColumns);
+			columnsFirst = columnsFirst.concat(customColumns);
 		}
 		
-		columns.push({
+		columnsFirst.push({
 			label : 'Space',
 			property : 'default_space',
 			isExportable: true,
-			sortable : true
+			sortable : false
 		});
 		
-		columns.push({
+		columnsFirst.push({
 			label : 'Parents',
 			property : 'parents',
 			isExportable: true,
-			sortable : true
+			sortable : false
 		});
 		
-		columns.push({
+		columnsFirst.push({
 			label : ELNDictionary.ExperimentELN + '/' + ELNDictionary.ExperimentInventory,
 			property : 'experiment',
 			isExportable: true,
-			sortable : true
+			sortable : false
 		});
 		
-		columns.push({
+		columnsFirst.push({
 			label : 'Preview',
 			property : 'preview',
 			isExportable: false,
@@ -109,81 +108,100 @@ var SampleDataGridUtil = new function() {
 			}
 		});
 		
-		var propertyColumnsToSort = [];
-		for (propertyCode in foundPropertyCodes) {
-			var propertiesToSkip = ["NAME", "XMLCOMMENTS", "ANNOTATIONS_STATE"];
-			if($.inArray(propertyCode, propertiesToSkip) !== -1) {
-				continue;
+		columnsFirst.push({
+			label : '---------------',
+			property : null,
+			isExportable: false,
+			sortable : false
+		});
+		
+		var dynamicColumnsFunc = function(samples) {
+			var foundPropertyCodes = {};
+			var foundSampleTypes = {};
+			for(var sIdx = 0; sIdx < samples.length; sIdx++) {
+				var sample = samples[sIdx];
+				if(!foundSampleTypes[sample.sampleTypeCode]) {
+					foundSampleTypes[sample.sampleTypeCode] = true;
+					var propertyCodes = profile.getAllPropertiCodesForTypeCode(sample.sampleTypeCode);
+					for(var pIdx = 0; pIdx < propertyCodes.length; pIdx++) {
+						foundPropertyCodes[propertyCodes[pIdx]] = true;
+					}
+				}
 			}
-			var propertyType = profile.getPropertyType(propertyCode);
-			if(propertyType.dataType === "CONTROLLEDVOCABULARY") {
-				var getVocabularyColumn = function(propertyType) {
-					return function() {
-						return {
-							label : propertyType.label,
-							property : propertyType.code,
-							isExportable: true,
-							sortable : true,
-							render : function(data) {
-								return FormUtil.getVocabularyLabelForTermCode(propertyType, data[propertyType.code]);
-							},
-							filter : function(data, filter) {
-								var value = FormUtil.getVocabularyLabelForTermCode(propertyType, data[propertyType.code]);
-								return value && value.toLowerCase().indexOf(filter) !== -1;
-							},
-							sort : function(data1, data2, asc) {
-								var value1 = FormUtil.getVocabularyLabelForTermCode(propertyType, data1[propertyType.code]);
-								if(!value1) {
-									value1 = ""
-								};
-								var value2 = FormUtil.getVocabularyLabelForTermCode(propertyType, data2[propertyType.code]);
-								if(!value2) {
-									value2 = ""
-								};
-								var sortDirection = (asc)? 1 : -1;
-								return sortDirection * naturalSort(value1, value2);
-							}
-						};
+			
+			var propertyColumnsToSort = [];
+			for (propertyCode in foundPropertyCodes) {
+				var propertiesToSkip = ["NAME", "XMLCOMMENTS", "ANNOTATIONS_STATE"];
+				if($.inArray(propertyCode, propertiesToSkip) !== -1) {
+					continue;
+				}
+				var propertyType = profile.getPropertyType(propertyCode);
+				if(propertyType.dataType === "CONTROLLEDVOCABULARY") {
+					var getVocabularyColumn = function(propertyType) {
+						return function() {
+							return {
+								label : propertyType.label,
+								property : propertyType.code,
+								isExportable: true,
+								sortable : true,
+								render : function(data) {
+									return FormUtil.getVocabularyLabelForTermCode(propertyType, data[propertyType.code]);
+								},
+								filter : function(data, filter) {
+									var value = FormUtil.getVocabularyLabelForTermCode(propertyType, data[propertyType.code]);
+									return value && value.toLowerCase().indexOf(filter) !== -1;
+								},
+								sort : function(data1, data2, asc) {
+									var value1 = FormUtil.getVocabularyLabelForTermCode(propertyType, data1[propertyType.code]);
+									if(!value1) {
+										value1 = ""
+									};
+									var value2 = FormUtil.getVocabularyLabelForTermCode(propertyType, data2[propertyType.code]);
+									if(!value2) {
+										value2 = ""
+									};
+									var sortDirection = (asc)? 1 : -1;
+									return sortDirection * naturalSort(value1, value2);
+								}
+							};
+						}
 					}
+					
+					var newVocabularyColumnFunc = getVocabularyColumn(propertyType);
+					propertyColumnsToSort.push(newVocabularyColumnFunc());
+				} else {			
+					propertyColumnsToSort.push({
+						label : propertyType.label,
+						property : propertyType.code,
+						isExportable: true,
+						sortable : true
+					});
 				}
-				
-				var newVocabularyColumnFunc = getVocabularyColumn(propertyType);
-				propertyColumnsToSort.push(newVocabularyColumnFunc());
-			} else {			
-				propertyColumnsToSort.push({
-					label : propertyType.label,
-					property : propertyType.code,
-					isExportable: true,
-					sortable : true
-				});
 			}
+
+			propertyColumnsToSort.sort(function(propertyA, propertyB) {
+				return propertyA.label.localeCompare(propertyB.label);
+			});
+			return propertyColumnsToSort;
 		}
 		
-		columns.push({
-			label : '---------------',
-			property : null,
-			isExportable: false,
-			sortable : false
-		});
-		propertyColumnsToSort.sort(function(propertyA, propertyB) {
-			return propertyA.label.localeCompare(propertyB.label);
-		});
-		columns = columns.concat(propertyColumnsToSort);
-		columns.push({
+		
+		var columnsLast = [];
+		columnsLast.push({
 			label : '---------------',
 			property : null,
 			isExportable: false,
 			sortable : false
 		});
 		
-		columns.push({
+		columnsLast.push({
 			label : 'Registration Date',
 			property : 'registrationDate',
 			isExportable: false,
 			sortable : true
 		});
 		
-		columns.push({
+		columnsLast.push({
 			label : 'Modification Date',
 			property : 'modificationDate',
 			isExportable: false,
@@ -191,23 +209,141 @@ var SampleDataGridUtil = new function() {
 		});
 		
 		if(!isOperationsDisabled && customOperations) {
-			columns.push(customOperations);
+			columnsLast.push(customOperations);
 		} else if(!isOperationsDisabled) {
-			columns.push(this.createOperationsColumn());
+			columnsLast.push(this.createOperationsColumn());
 		}
 		
 		//Fill data model
-		var getDataList = SampleDataGridUtil.getDataList(samples);
+		var getDataList = null;
+		if(samplesOrCriteria.entityKind && samplesOrCriteria.rules) {
+			getDataList = SampleDataGridUtil.getDataListDynamic(samplesOrCriteria); //Load on demand model
+		} else {
+			getDataList = SampleDataGridUtil.getDataList(samplesOrCriteria); //Static model
+		}
 			
 		//Create and return a data grid controller
 		var configKey = "SAMPLE_TABLE_" + mandatoryConfigPostKey;
 		if(optionalConfigPostKey) {
 			configKey += "_" + optionalConfigPostKey;
 		}
-		var dataGridController = new DataGridController(null, columns, getDataList, rowClick, false, configKey, isMultiselectable);
+		
+		var dataGridController = new DataGridController(null, columnsFirst, columnsLast, dynamicColumnsFunc, getDataList, rowClick, false, configKey, isMultiselectable);
 		return dataGridController;
 	}
 	
+	this.getDataListDynamic = function(criteria) {
+		return function(callback, options) {
+			var callbackForSearch = function(result) {
+				var dataList = [];
+				
+				for(var sIdx = 0; sIdx < result.objects.length; sIdx++) {
+					var sample = mainController.serverFacade.getV3SampleAsV1(result.objects[sIdx]);
+					
+					var registrationDate = null;
+					if(sample.registrationDetails && sample.registrationDetails.registrationDate) {
+						registrationDate = Util.getFormatedDate(new Date(sample.registrationDetails.registrationDate));
+					}
+					
+					var modificationDate = null;
+					if(sample.registrationDetails && sample.registrationDetails.modificationDate) {
+						modificationDate = Util.getFormatedDate(new Date(sample.registrationDetails.modificationDate));
+					}
+					
+					var sampleModel = { 
+										'$object' : sample,
+										'identifier' : sample.identifier, 
+										'code' : sample.code,
+										'sampleTypeCode' : sample.sampleTypeCode,
+										'default_space' : sample.spaceCode,
+										'permId' : sample.permId,
+										'experiment' : sample.experimentIdentifierOrNull,
+										'registrationDate' : registrationDate,
+										'modificationDate' : modificationDate
+									};
+					
+					if(sample.properties) {
+						for(var propertyCode in sample.properties) {
+							sampleModel[propertyCode] = sample.properties[propertyCode];
+						}
+					}
+					
+					var parents = "";
+					if(sample.parents) {
+						for (var paIdx = 0; paIdx < sample.parents.length; paIdx++) {
+							if(paIdx !== 0) {
+								parents += ", ";
+							}
+							parents += sample.parents[paIdx].identifier;
+						}
+					}
+					
+					sampleModel['parents'] = parents;
+					
+					dataList.push(sampleModel);
+				}
+				
+				callback({
+					objects : dataList,
+					totalCount : result.totalCount
+				});
+			}
+			
+			var fetchOptions = {};
+			
+			if(options) {
+				fetchOptions.count = options.pageSize;
+				fetchOptions.from = options.pageIndex * options.pageSize;
+			}
+			
+			if(!criteria.cached) {
+				fetchOptions.cache = "RELOAD_AND_CACHE";
+				criteria.cached = true;
+			} else {
+				fetchOptions.cache = "CACHE";
+			}
+				
+			var criteriaToSend = $.extend(true, {}, criteria);
+			
+			if(options.search) {
+				var filter = options.search.toLowerCase().split(/[ ,]+/); //Split by regular space or comma
+				for(var fIdx = 0; fIdx < filter.length; fIdx++) {
+					var fKeyword = filter[fIdx];
+					criteriaToSend.rules[Util.guid()] = { type : "All", name : "", value : fKeyword };
+				}
+			}
+			
+			if(options.sortProperty && options.sortDirection) {
+				fetchOptions.sort = { 
+						type : null,
+						name : null,
+						direction : options.sortDirection
+				}
+				switch(options.sortProperty) {
+					case "code":
+						fetchOptions.sort.type = "Attribute";
+						fetchOptions.sort.name = "code";
+						break;
+					case "registrationDate":
+						fetchOptions.sort.type = "Attribute";
+						fetchOptions.sort.name = "registrationDate"
+						
+						break;
+					case "modificationDate":
+						fetchOptions.sort.type = "Attribute";
+						fetchOptions.sort.name = "modificationDate";
+						break;
+					default: //Properties
+						fetchOptions.sort.type = "Property";
+						fetchOptions.sort.name = options.sortProperty;
+						break;
+				}
+			}
+			
+			mainController.serverFacade.searchForSamplesAdvanced(criteriaToSend, fetchOptions, callbackForSearch);
+		}
+	}
+	
 	this.getDataList = function(samples) {
 		return function(callback) {
 			var dataList = [];
@@ -226,6 +362,8 @@ var SampleDataGridUtil = new function() {
 				
 				var sampleModel = { '$object' : sample,
 									'identifier' : sample.identifier, 
+									'code' : sample.code,
+									'sampleTypeCode' : sample.sampleTypeCode,
 									'default_space' : sample.spaceCode,
 									'permId' : sample.permId,
 									'experiment' : sample.experimentIdentifierOrNull,
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/Export/ExportTreeView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/Export/ExportTreeView.js
index 7bf00a9b71c..6682aedfbc9 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/Export/ExportTreeView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/Export/ExportTreeView.js
@@ -79,7 +79,7 @@ function ExportTreeView(exportTreeController, exportTreeModel) {
     	    switch(type) {
     	    	case "ROOT":
     	    		var spaceRules = { entityKind : "SPACE", logicalOperator : "AND", rules : { } };
-    	    		mainController.serverFacade.searchForSpacesAdvanced(spaceRules, function(searchResult) {
+    	    		mainController.serverFacade.searchForSpacesAdvanced(spaceRules, null, function(searchResult) {
     	    			var results = [];
     	                var spaces = searchResult.objects;
     	                for (var i = 0; i < spaces.length; i++) {
@@ -91,7 +91,7 @@ function ExportTreeView(exportTreeController, exportTreeModel) {
     	    		break;
     	    	case "SPACE":
     	    		var projectRules = { "UUIDv4" : { type : "Attribute", name : "SPACE", value : permId } };
-    	    		mainController.serverFacade.searchForProjectsAdvanced({ entityKind : "PROJECT", logicalOperator : "AND", rules : projectRules }, function(searchResult) {
+    	    		mainController.serverFacade.searchForProjectsAdvanced({ entityKind : "PROJECT", logicalOperator : "AND", rules : projectRules }, null, function(searchResult) {
     	    			var results = [];
     	                var projects = searchResult.objects;
     	                for (var i = 0; i < projects.length; i++) {
@@ -103,7 +103,7 @@ function ExportTreeView(exportTreeController, exportTreeModel) {
     	    		break;
     	    	case "PROJECT":
     	    		var experimentRules = { "UUIDv4" : { type : "Attribute", name : "PROJECT_PERM_ID", value : permId } };
-    	    		mainController.serverFacade.searchForExperimentsAdvanced({ entityKind : "EXPERIMENT", logicalOperator : "AND", rules : experimentRules }, function(searchResult) {
+    	    		mainController.serverFacade.searchForExperimentsAdvanced({ entityKind : "EXPERIMENT", logicalOperator : "AND", rules : experimentRules }, null, function(searchResult) {
     	    			var results = [];
     	                var experiments = searchResult.objects;
     	                for (var i = 0; i < experiments.length; i++) {
@@ -115,7 +115,7 @@ function ExportTreeView(exportTreeController, exportTreeModel) {
     	    		break;
     	    	case "EXPERIMENT":
     	    		var sampleRules = { "UUIDv4" : { type : "Experiment", name : "ATTR.PERM_ID", value : permId } };
-    	    		mainController.serverFacade.searchForSamplesAdvanced({ entityKind : "SAMPLE", logicalOperator : "AND", rules : sampleRules }, function(searchResult) {
+    	    		mainController.serverFacade.searchForSamplesAdvanced({ entityKind : "SAMPLE", logicalOperator : "AND", rules : sampleRules }, null, function(searchResult) {
     	    			var results = [];
     	                var samples = searchResult.objects;
     	                for (var i = 0; i < samples.length; i++) {
@@ -127,7 +127,7 @@ function ExportTreeView(exportTreeController, exportTreeModel) {
     	    		break;
     	    	case "SAMPLE":
     	    		var datasetRules = { "UUIDv4" : { type : "Sample", name : "ATTR.PERM_ID", value : permId } };
-    	    		mainController.serverFacade.searchForDataSetsAdvanced({ entityKind : "DATASET", logicalOperator : "AND", rules : datasetRules }, function(searchResult) {
+    	    		mainController.serverFacade.searchForDataSetsAdvanced({ entityKind : "DATASET", logicalOperator : "AND", rules : datasetRules }, null, function(searchResult) {
     	    			var results = [];
     	                var datasets = searchResult.objects;
     	                for (var i = 0; i < datasets.length; i++) {
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/LinksView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/LinksView.js
index 9788808bc7f..5f2f3c72e35 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/LinksView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/LinksView.js
@@ -20,7 +20,6 @@ function LinksView(linksController, linksModel) {
 	var linksView = this;
 	
 	var sampleGridContainerByType = {};
-	var samplesByTypeCache = {};
 	
 	var $samplePicker = $("<div>");
 	var $savedContainer = null;
@@ -356,33 +355,27 @@ function LinksView(linksController, linksModel) {
 		$container.append($gridContainer);
 		
 		//Show Table Logic
-		var showTableFunction = function(samples) {
-			samplesByTypeCache[sampleTypeCode] = samples;
-			
-			var rowClick = function(e) {
-				linksController.addSample(e.data["$object"]);
-				$container.empty().hide();
+		var extraOptions = [];
+		extraOptions.push({ name : "Add selected", action : function(selected) {
+			for(var sIdx = 0; sIdx < selected.length; sIdx++) {
+				linksController.addSample(selected[sIdx]);
 			}
-			
-			var extraOptions = [];
-			extraOptions.push({ name : "Add selected", action : function(selected) {
-				for(var sIdx = 0; sIdx < selected.length; sIdx++) {
-					linksController.addSample(selected[sIdx]);
-				}
-				$container.empty().hide();
-			}});
-			
-			var dataGrid = SampleDataGridUtil.getSampleDataGrid(sampleTypeCode, samples, rowClick, null, null, null, true, true, true);
-			dataGrid.init($gridContainer, extraOptions);
+			$container.empty().hide();
+		}});
+		
+		var advancedSampleSearchCriteria = {
+				entityKind : "SAMPLE",
+				logicalOperator : "AND",
+				rules : { "1" : { type : "Attribute", name : "SAMPLE_TYPE", value : sampleTypeCode } }
 		}
 		
-		//Check Cache and Show Table
-		var sampleTypeCache = samplesByTypeCache[sampleTypeCode];
-		if(sampleTypeCache) {
-			showTableFunction(sampleTypeCache);
-		} else {
-			mainController.serverFacade.searchWithType(sampleTypeCode, null, false, showTableFunction);
+		var rowClick = function(e) {
+			linksController.addSample(e.data["$object"]);
+			$container.empty().hide();
 		}
+		
+		var dataGrid = SampleDataGridUtil.getSampleDataGrid(sampleTypeCode, advancedSampleSearchCriteria, rowClick, null, null, null, true, true, true);
+		dataGrid.init($gridContainer, extraOptions);
 	}
 			
 	linksView.getAddBtn = function($container, sampleTypeCode) {
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/StorageListView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/StorageListView.js
index 43af3f46991..f3e52b43999 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/StorageListView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/StorageListView.js
@@ -97,7 +97,7 @@ function StorageListView(storageListController, storageListModel) {
 			}
 		}
 		
-		this._dataGrid = new DataGridController(null, columns, getDataList, rowClick, false, "STORAGE_WIDGET");
+		this._dataGrid = new DataGridController(null, columns, [], null, getDataList, rowClick, false, "STORAGE_WIDGET");
 		
 		var $dataGridContainer = $("<div>");
 		this._dataGrid.init($dataGridContainer);
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleHierarchyTable/SampleHierarchyTableView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleHierarchyTable/SampleHierarchyTableView.js
index 5939c97f633..bb02bd0dbd9 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleHierarchyTable/SampleHierarchyTableView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleHierarchyTable/SampleHierarchyTableView.js
@@ -103,7 +103,7 @@ function SampleHierarchyTableView(controller, model) {
 			mainController.changeView('showViewSamplePageFromPermId', e.data.permId);
 		}
 		
-		this._dataGrid = new DataGridController(null, columns, getDataList, rowClick, false, "SAMPLE_HIERARCHY_TABLE");
+		this._dataGrid = new DataGridController(null, columns, [], null, getDataList, rowClick, false, "SAMPLE_HIERARCHY_TABLE");
 		this._dataGrid.init(this._container);
 		this._container.prepend($("<legend>").append(" " + ELNDictionary.Sample + " Hierarchy"));
 	}
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableController.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableController.js
index 1972be4b645..76202417ca7 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableController.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableController.js
@@ -43,47 +43,34 @@ function SampleTableController(parentController, title, experimentIdentifier, pr
 			properyKeyValueList = [{ "SHOW_IN_PROJECT_OVERVIEW" : "\"true\"" }];
 		}
 		
-		mainController.serverFacade.searchWithExperiment(this._sampleTableModel.experimentIdentifier, this._sampleTableModel.projectPermId, properyKeyValueList, function(experimentSamples) {
-			_this._sampleTableModel.allSamples = experimentSamples;
-			for(var i = 0; i < experimentSamples.length; i++) {
-				if(_this._sampleTableModel.sampleTypes[experimentSamples[i].sampleTypeCode]) {
-					_this._sampleTableModel.sampleTypes[experimentSamples[i].sampleTypeCode] = _this._sampleTableModel.sampleTypes[experimentSamples[i].sampleTypeCode] + 1;
-				} else {
-					_this._sampleTableModel.sampleTypes[experimentSamples[i].sampleTypeCode] = 1;
-				}
-			}
-			callback();
-			
-			//Show samples when only one type available by default
-			var numSampleTypes = 0;
-			var defaultSampleType = null;
-			for(sampleTypeCode in _this._sampleTableModel.sampleTypes) {
-				if(numSampleTypes === 0) {
-					defaultSampleType = sampleTypeCode;
-				}
-				numSampleTypes++;
+		//
+		var advancedSampleSearchCriteria = null;
+		
+		if(this._sampleTableModel.experiment) {
+			advancedSampleSearchCriteria = {
+					entityKind : "SAMPLE",
+					logicalOperator : "AND",
+					rules : { "1" : { type : "Experiment", name : "ATTR.PERM_ID", value : this._sampleTableModel.experiment.permId } }
 			}
-			
-			if(numSampleTypes === 1) {
-				_this._reloadTableWithSampleType(defaultSampleType);
-				_this._sampleTableView.getSampleTypeSelector().val(defaultSampleType);
+		} else if(this._sampleTableModel.projectPermId) {
+			advancedSampleSearchCriteria = {
+					entityKind : "SAMPLE",
+					logicalOperator : "AND",
+					rules : { "1" : { type : "Experiment", name : "ATTR.PROJECT_PERM_ID", value : this._sampleTableModel.projectPermId } }
 			}
-		});
+		}
+		
+		if(this._sampleTableModel.showInProjectOverview) {
+			advancedSampleSearchCriteria.rules["2"] = { type : "Property", name : "SHOW_IN_PROJECT_OVERVIEW", value : "true" };
+		}
+		//
+		callback();
+		this._reloadTableWithAllSamples(advancedSampleSearchCriteria);
 	}
 	
-	this._reloadTableWithSampleType = function(selectedSampleTypeCode) {
-		if(selectedSampleTypeCode !== '') { //Verify something selected
-			//Get samples from type
-			var samples = [];
-			for (var idx = 0; idx < this._sampleTableModel.allSamples.length; idx++) {
-				var sampleToCheckType = this._sampleTableModel.allSamples[idx];
-				if(sampleToCheckType.sampleTypeCode === selectedSampleTypeCode) {
-					samples.push(sampleToCheckType);
-				}
-			}
-			
+	this._reloadTableWithAllSamples = function(advancedSampleSearchCriteria) {
 			//Create and display table
-			var dataGridController = SampleDataGridUtil.getSampleDataGrid(selectedSampleTypeCode, samples, null, null, null, null, null, null, true);
+			var dataGridController = SampleDataGridUtil.getSampleDataGrid(this._sampleTableModel.experimentIdentifier, advancedSampleSearchCriteria, null, null, null, null, null, null, true);
 			
 			
 			var extraOptions = [];
@@ -115,6 +102,5 @@ function SampleTableController(parentController, title, experimentIdentifier, pr
 			}});
 			
 			dataGridController.init(this._sampleTableView.getTableContainer(), extraOptions);
-		}
 	}
 }
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableModel.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableModel.js
index 087055f28d5..b29556610c4 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableModel.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableModel.js
@@ -20,6 +20,5 @@ function SampleTableModel(title, experimentIdentifier, projectPermId, showInProj
 	this.experiment = experiment;
 	this.projectPermId = projectPermId;
 	this.showInProjectOverview = showInProjectOverview;
-	this.sampleTypes = {};
 	this.allSamples = new Array();
 }
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableView.js
index 89bc8007da7..1ba497370e0 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleTable/SampleTableView.js
@@ -76,21 +76,26 @@ function SampleTableView(sampleTableController, sampleTableModel) {
 		
 		var tableToolbarModel = [];
 		if(this._sampleTableModel.experimentIdentifier) {
-			var $sampleTypes = this._getLoadedSampleTypesDropdown();
-			tableToolbarModel.push({ component : $sampleTypes, tooltip: null });
 			var $options = this._getOptionsMenu();
 			toolbarModel.push({ component : $options, tooltip: null });
 		} else if(this._sampleTableModel.projectPermId) {
-			var $sampleTypes = this._getLoadedSampleTypesDropdown();
-			tableToolbarModel.push({ component : $sampleTypes, tooltip: null });
+
 		} else {
 			var $allSampleTypes = this._getAllSampleTypesDropdown();
 			tableToolbarModel.push({ component : $allSampleTypes, tooltip: null });
 		}
 		
-		$container.append(FormUtil.getToolbar(toolbarModel));
-		$container.append("<br>");
-		$container.append(FormUtil.getToolbar(tableToolbarModel));
+		if(toolbarModel.length > 0) {
+			$container.append(FormUtil.getToolbar(toolbarModel));
+		}
+		if(toolbarModel.length > 0 && tableToolbarModel.length > 0) {
+			$container.append("<br>");
+		}
+		if(tableToolbarModel.length > 0) {
+			$container.append(FormUtil.getToolbar(tableToolbarModel));
+		}
+		
+		
 		$container.append(this._tableContainer);
 	}
 	
@@ -98,13 +103,6 @@ function SampleTableView(sampleTableController, sampleTableModel) {
 		return this._tableContainer;
 	}
 	
-	//
-	// Components
-	//
-	this.getSampleTypeSelector = function() {
-		return this.sampleTypeSelector;
-	}
-	
 	//
 	// Menus
 	//
@@ -137,33 +135,19 @@ function SampleTableView(sampleTableController, sampleTableModel) {
 		return $dropDownMenu;
 	}
 	
-	this._getLoadedSampleTypesDropdown = function() {
-		var _this = this;
-		var	$sampleTypesSelector = $('<select>', { 'id' : 'sampleTypeCodesToShow', class : 'form-control' });
-		$sampleTypesSelector.append($("<option>").attr('value', '').attr('selected', '').attr('disabled', '').text("Select an " + ELNDictionary.sample + " type"));
-		for(sampleTypeCode in this._sampleTableModel.sampleTypes) {
-			$sampleTypesSelector.append($('<option>', { 'value' : sampleTypeCode }).text(sampleTypeCode));
-		}
-		
-		$sampleTypesSelector.change(function(event) {
-			var sampleTypeToShow = $(this).val();
-			_this._sampleTableController._reloadTableWithSampleType(sampleTypeToShow);
-		});
-		this.sampleTypeSelector = $sampleTypesSelector;
-		return $("<span>").append($sampleTypesSelector);
-	}
-	
 	this._getAllSampleTypesDropdown = function() {
 		var _this = this;
 		var $sampleTypesSelector = FormUtil.getSampleTypeDropdown(null, false);
 		$sampleTypesSelector.change(function() {
 			var sampleTypeToShow = $(this).val();
-			Util.blockUI();
-			mainController.serverFacade.searchByTypeWithParents(sampleTypeToShow, function(samples) {
-				_this._sampleTableModel.allSamples = samples;
-				_this._sampleTableController._reloadTableWithSampleType(sampleTypeToShow);
-				Util.unblockUI();
-			});
+			
+			var advancedSampleSearchCriteria = {
+					entityKind : "SAMPLE",
+					logicalOperator : "AND",
+					rules : { "1" : { type : "Attribute", name : "SAMPLE_TYPE", value : sampleTypeToShow } }
+			}
+			
+			_this._sampleTableController._reloadTableWithAllSamples(advancedSampleSearchCriteria);
 		});
 		
 		return $("<span>").append($sampleTypesSelector);
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js
index 1b52d4950ce..756ed372070 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js
@@ -293,7 +293,7 @@ function SideMenuWidgetView(sideMenuWidgetController, sideMenuWidgetModel) {
     	    	case "LAB_NOTEBOOK":
     	    	case "INVENTORY":
     	    		var spaceRules = { entityKind : "SPACE", logicalOperator : "AND", rules : { } };
-    	    		mainController.serverFacade.searchForSpacesAdvanced(spaceRules, function(searchResult) {
+    	    		mainController.serverFacade.searchForSpacesAdvanced(spaceRules, null, function(searchResult) {
     	    			var results = [];
     	                var spaces = searchResult.objects;
     	                for (var i = 0; i < spaces.length; i++) {
@@ -314,7 +314,7 @@ function SideMenuWidgetView(sideMenuWidgetController, sideMenuWidgetModel) {
     	    		break;
     	    	case "SPACE":
     	    		var projectRules = { "UUIDv4" : { type : "Attribute", name : "SPACE", value : permId } };
-    	    		mainController.serverFacade.searchForProjectsAdvanced({ entityKind : "PROJECT", logicalOperator : "AND", rules : projectRules }, function(searchResult) {
+    	    		mainController.serverFacade.searchForProjectsAdvanced({ entityKind : "PROJECT", logicalOperator : "AND", rules : projectRules }, null, function(searchResult) {
     	    			var results = [];
     	                var projects = searchResult.objects;
     	                for (var i = 0; i < projects.length; i++) {
@@ -328,7 +328,7 @@ function SideMenuWidgetView(sideMenuWidgetController, sideMenuWidgetModel) {
     	    		break;
     	    	case "PROJECT":
     	    		var experimentRules = { "UUIDv4" : { type : "Attribute", name : "PROJECT_PERM_ID", value : permId } };
-    	    		mainController.serverFacade.searchForExperimentsAdvanced({ entityKind : "EXPERIMENT", logicalOperator : "AND", rules : experimentRules }, function(searchResult) {
+    	    		mainController.serverFacade.searchForExperimentsAdvanced({ entityKind : "EXPERIMENT", logicalOperator : "AND", rules : experimentRules }, null, function(searchResult) {
     	    			var results = [];
     	                var experiments = searchResult.objects;
     	                for (var i = 0; i < experiments.length; i++) {
@@ -355,7 +355,7 @@ function SideMenuWidgetView(sideMenuWidgetController, sideMenuWidgetModel) {
     	    		break;
     	    	case "EXPERIMENT":
     	    		var sampleRules = { "UUIDv4" : { type : "Experiment", name : "ATTR.PERM_ID", value : permId } };
-    	    		mainController.serverFacade.searchForSamplesAdvanced({ entityKind : "SAMPLE", logicalOperator : "AND", rules : sampleRules }, 
+    	    		mainController.serverFacade.searchForSamplesAdvanced({ entityKind : "SAMPLE", logicalOperator : "AND", rules : sampleRules }, null,
     	    		function(searchResult) {
     	    			var samples = searchResult.objects;
     	    			
@@ -401,7 +401,7 @@ function SideMenuWidgetView(sideMenuWidgetController, sideMenuWidgetModel) {
     	    		break;
     	    	case "SAMPLE":
     	    		var datasetRules = { "UUIDv4" : { type : "Sample", name : "ATTR.PERM_ID", value : permId } };
-    	    		mainController.serverFacade.searchForDataSetsAdvanced({ entityKind : "DATASET", logicalOperator : "AND", rules : datasetRules }, function(searchResult) {
+    	    		mainController.serverFacade.searchForDataSetsAdvanced({ entityKind : "DATASET", logicalOperator : "AND", rules : datasetRules }, null, function(searchResult) {
     	    			var results = [];
     	                var datasets = searchResult.objects;
     	                
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/TrashManager/TrashManagerView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/TrashManager/TrashManagerView.js
index 3940ec634c2..61601680a93 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/TrashManager/TrashManagerView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/TrashManager/TrashManagerView.js
@@ -175,7 +175,7 @@ function TrashManagerView(trashManagerController, trashManagerModel) {
 		}
 		
 		var dataGridContainer = $("<div>");
-		var dataGrid = new DataGridController(null, columns, getDataList, null, true, "TRASHCAN_TABLE");
+		var dataGrid = new DataGridController(null, columns, [], null, getDataList, null, true, "TRASHCAN_TABLE");
 		dataGrid.init(dataGridContainer);
 		$containerColumn.append(dataGridContainer);
 		
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserManager/UserManagerView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserManager/UserManagerView.js
index d69da49d13c..3b48802038e 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserManager/UserManagerView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/UserManager/UserManagerView.js
@@ -123,7 +123,7 @@ function UserManagerView(userManagerController, userManagerModel) {
 			callback(dataList);
 		}
 		
-		var dataGrid = new DataGridController(null, columns, getDataList, null, false, "USER_MANAGER_TABLE");
+		var dataGrid = new DataGridController(null, columns, [], null, getDataList, null, false, "USER_MANAGER_TABLE");
 		dataGrid.init(dataGridContainer);
 		
 		//
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/VocabularyManager/VocabularyManagerView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/VocabularyManager/VocabularyManagerView.js
index 4369b9f5daf..16cdc89ae88 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/VocabularyManager/VocabularyManagerView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/VocabularyManager/VocabularyManagerView.js
@@ -70,7 +70,7 @@ function VocabularyManagerView(vocabularyManagerController, vocabularyManagerMod
 			_this._showVocabulary(e.data.object)
 		}
 		
-		var dataGrid = new DataGridController(null, columns, getDataList, rowClick, true, "VOCABULARY_TABLE");
+		var dataGrid = new DataGridController(null, columns, [], null, getDataList, rowClick, true, "VOCABULARY_TABLE");
 		dataGrid.init(this._dataGridContainer);
 		
 		this._subtitle.empty();
@@ -106,7 +106,7 @@ function VocabularyManagerView(vocabularyManagerController, vocabularyManagerMod
 			callback(dataList);
 		}
 		
-		var dataGrid = new DataGridController(null, columns, getDataList, null, true, "VOCABULARY_TERMS_TABLE");
+		var dataGrid = new DataGridController(null, columns, [], null, getDataList, null, true, "VOCABULARY_TERMS_TABLE");
 		dataGrid.init(this._dataGridContainer);
 		
 		this._subtitle.empty();
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/grid/js/Grid.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/grid/js/Grid.js
index dc71368bc0d..348fdebfba4 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/grid/js/Grid.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/grid/js/Grid.js
@@ -1,10 +1,13 @@
-function Grid(columns, getDataList, showAllColumns, tableSettings, onChangeState, isMultiselectable) {
-	this.init(columns, getDataList, showAllColumns, tableSettings, onChangeState, isMultiselectable);
+function Grid(columnsFirst, columnsLast, columnsDynamicFunc, getDataList, showAllColumns, tableSettings, onChangeState, isMultiselectable) {
+	this.init(columnsFirst, columnsLast, columnsDynamicFunc, getDataList, showAllColumns, tableSettings, onChangeState, isMultiselectable);
 }
 
 $.extend(Grid.prototype, {
-	init : function(columns, getDataList, showAllColumns, tableSettings, onChangeState, isMultiselectable) {
-		this.columns = columns;
+	init : function(columnsFirst, columnsLast, columnsDynamicFunc, getDataList, showAllColumns, tableSettings, onChangeState, isMultiselectable) {
+		this.columnsFirst = columnsFirst;
+		this.columnsDynamicFunc = columnsDynamicFunc;
+		this.columnsDynamic = [];
+		this.columnsLast = columnsLast;
 		this.getDataList = getDataList;
 		this.showAllColumns = showAllColumns;
 		this.tableSettings = tableSettings;
@@ -23,7 +26,7 @@ $.extend(Grid.prototype, {
 		this.isMultiselectable = isMultiselectable;
 		this.selectedItems = [];
 		if(isMultiselectable) {
-			this.addMultiSelect(columns);
+			this.addMultiSelect(columnsFirst);
 		}
 	},
 	addMultiSelect : function(columns) {
@@ -31,26 +34,7 @@ $.extend(Grid.prototype, {
 		columns.unshift({
 				showByDefault: true,
 				label : function() {
-					var $selectall = $("<input>", { type : 'checkbox' });
-					$selectall.change(function(){
-						var allCheckboxes = _this.panel.find(".multi-selectable-checkbox");
-						var isChecked = $(this).is(":checked");
-						//check / uncheck all
-						allCheckboxes.each(function() { 
-			                this.checked = isChecked;
-			            });
-						//If check, add to the selectedItems list
-						_this.selectedItems = [];
-						if(isChecked) { //select all
-							_this.getDataList(function(dataList) {
-								for(var dIdx = 0; dIdx < dataList.length; dIdx++) {
-									_this.selectedItems.push(dataList[dIdx].$object);
-								}
-							});
-						}
-					});
-					
-					return $selectall;
+					return "";
 				},
 				property : '$selected',
 				isExportable: false,
@@ -109,7 +93,6 @@ $.extend(Grid.prototype, {
 			template = template.replace(templateToReplace, templateToReplaceFor);
 			//
 			thisGrid.panel.html(template);
-			thisGrid.renderColumnDropdown();
 			thisGrid.renderDropDownOptions();
 			
 			if(thisGrid.rowClickListeners && thisGrid.rowClickListeners.length > 0) {
@@ -159,17 +142,20 @@ $.extend(Grid.prototype, {
 		return thisGrid.panel;
 	},
 
-	renderColumnDropdown : function() {
+	renderColumnDropdown : function(columnsForDropdown) {
 		var thisGrid = this;
 
 		var columnList = thisGrid.panel.find(".columnDropdown").find("ul");
+		columnList.empty();
 		columnList.click(function(e) {
 			e.stopPropagation();
 		});
 		
 		var defaultNumColumns = 5; //Including last always
 		
-		thisGrid.columns.forEach(function(column, columnIndex) {
+		var currentColumns = this.getAllColumns();
+		
+		columnsForDropdown.forEach(function(column, columnIndex) {
 			if(!column.showByDefault) {
 				var checkbox = $("<input>")
 				.attr("type", "checkbox")
@@ -180,12 +166,17 @@ $.extend(Grid.prototype, {
 					if((thisGrid.tableSettings.columns[column.property] === true)) { //If settings are present
 						checkbox.attr("checked", "checked");
 					}
-				} else if(thisGrid.showAllColumns || columnIndex < (defaultNumColumns - 1) || (columnIndex+1 === thisGrid.columns.length)) { //Defaults
+				} else if(thisGrid.showAllColumns || columnIndex < (defaultNumColumns - 1) || (columnIndex+1 === currentColumns.length)) { //Defaults
 					checkbox.attr("checked", "checked");
 				}
 				
-				checkbox.change(function() {
+				checkbox.change(function(e) {
+					var $checkbox = $(this);
+					var propertyName = $checkbox.prop('value');
+					var isChecked = $checkbox.prop('checked');
+					thisGrid.tableSettings.columns[propertyName] = isChecked;
 					thisGrid.panel.repeater('render');
+					e.stopPropagation();
 				});
 				var label = $("<label>", { style : 'white-space: nowrap;' }).attr("role", "menuitem").append(checkbox).append("&nbsp;").append(column.label);
 				var item = $("<li>").attr("role", "presentation").append(label);
@@ -195,7 +186,7 @@ $.extend(Grid.prototype, {
 	},
 
 	getAllColumns : function() {
-		return this.columns;
+		return this.columnsFirst.concat(this.columnsDynamic).concat(this.columnsLast);
 	},
 
 	addExtraOptions : function(extraOptions) {
@@ -331,7 +322,9 @@ $.extend(Grid.prototype, {
 		var thisGrid = this;
 		
 		var exportColumnsFromData = function(namePrefix, data, headings) {
-			
+			if(data.objects) {
+				data = data.objects
+			}
 			var arrayOfRowArrays = [];
 			arrayOfRowArrays.push(headings);
 			for(var dIdx = 0; dIdx < data.length; dIdx++) {
@@ -386,8 +379,10 @@ $.extend(Grid.prototype, {
 		var headings = [];
 		var data = [];
 		var prefix = "";
+		
 		if(isAllColumnsOrVisible) {
-			thisGrid.columns.forEach(function(head) {
+			var currentColumns = this.getAllColumns();
+			currentColumns.forEach(function(head) {
 				if(head.isExportable === true || head.isExportable === undefined) {
 					headings.push(head.property);
 				}
@@ -447,14 +442,14 @@ $.extend(Grid.prototype, {
 
 	filterData : function(dataList, filter) {
 		var thisGrid = this;
-
+		var currentColumns = this.getAllColumns();
 		if (filter) {
 			filterKeywords = filter.toLowerCase().split(/[ ,]+/); //Split by regular space or comma
 			dataList = dataList.filter(function(data) {
 				var isValid = new Array(filterKeywords.length);
 				
-				for(cIdx = 0; cIdx < thisGrid.columns.length; cIdx++) {
-					var column = thisGrid.columns[cIdx];
+				for(cIdx = 0; cIdx < currentColumns.length; cIdx++) {
+					var column = currentColumns[cIdx];
 					for(var fIdx = 0; fIdx < filterKeywords.length; fIdx++) {
 						var filterKeyword = filterKeywords[fIdx];
 						if (column.filter) {
@@ -493,7 +488,8 @@ $.extend(Grid.prototype, {
 			//
 			
 			var sortColumn = null;
-			thisGrid.columns.forEach(function(column) {
+			var currentColumns = this.getAllColumns();
+			currentColumns.forEach(function(column) {
 				if (column.property == sortProperty) {
 					sortColumn = column;
 				}
@@ -526,9 +522,11 @@ $.extend(Grid.prototype, {
 		var items = [];
 		var maxLineLength = 200;
 		
+		var visibleColumns = thisGrid.getVisibleColumns();
+		
 		dataList.forEach(function(data) {
 			var item = {};
-			thisGrid.getVisibleColumns().forEach(function(column) {
+			visibleColumns.forEach(function(column) {
 				//1. Render
 				var value = null;
 				if (column.render) {
@@ -566,23 +564,55 @@ $.extend(Grid.prototype, {
 
 	list : function(options, callback) {
 		var thisGrid = this;
-		thisGrid.getDataList(function(dataList) {
+		
+		thisGrid.getDataList(function(dataListResult) {
+			dataList = null;
+			var isDynamic = (dataListResult.totalCount != null && dataListResult.totalCount != undefined);
+			
+			if(isDynamic) {
+				dataList = dataListResult.objects;		
+				
+				if(thisGrid.onChangeState && thisGrid.tableSettings) {
+					thisGrid.tableSettings.sort = {
+							sortProperty : options.sortProperty,
+							sortDirection : options.sortDirection
+					};
+					thisGrid.onChangeState(thisGrid.tableSettings);
+				}
+				
+			} else { //Used for static tables filtering and sorting, on dynamic ones it happens on the getDataList function given the options
+				dataList = dataListResult;
+				dataList = thisGrid.filterData(dataList, options.search);
+				dataList = thisGrid.sortData(dataList, options.sortProperty, options.sortDirection);
+			}
 			
-			dataList = thisGrid.filterData(dataList, options.search);
-			dataList = thisGrid.sortData(dataList, options.sortProperty, options.sortDirection);
 
 			var result = {};
-			result.count = dataList.length;
+			
+			if(isDynamic) {
+				result.count = dataListResult.totalCount;
+			} else {
+				result.count = dataList.length;
+			}
+			
 			result.datas = [];
 			result.items = [];
-			result.columns = thisGrid.getVisibleColumns();
+			
 			result.page = options.pageIndex;
 			result.pages = Math.ceil(result.count / options.pageSize);
 			result.start = options.pageIndex * options.pageSize;
 			result.end = result.start + options.pageSize;
 			result.end = (result.end <= result.count) ? result.end : result.count;
 			
-			dataList = dataList.slice(result.start, result.end);
+			if(!isDynamic) {
+				dataList = dataList.slice(result.start, result.end);
+			}
+			
+			if(thisGrid.columnsDynamicFunc) {
+				thisGrid.columnsDynamic = thisGrid.columnsDynamicFunc(dataList);
+			}
+			thisGrid.renderColumnDropdown(thisGrid.getAllColumns());
+			result.columns = thisGrid.getVisibleColumns();
 			
 			if(dataList.length === 0) { //Special case, empty table
 				result.start = 0;
@@ -632,8 +662,9 @@ $.extend(Grid.prototype, {
 						$parent.css("cursor", "initial");
 					}
 				}
+				
 			}, 1);
-		});
+		}, options);
 	},
 
 	addRowClickListener : function(listener) {
-- 
GitLab