diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/elnTypes.py b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/elnTypes.py index ecf4c7a39e673c742524de51a83e9efb2f478e74..1f79772db22e9aa91f6538f4f87f96b3fed25657 100644 --- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/elnTypes.py +++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/elnTypes.py @@ -860,13 +860,6 @@ FLY = [FIRST_TIME_VERSIONED, True, True, "FLY", "", [ [FIRST_TIME_VERSIONED, "ANNOTATIONS_STATE", "Comments", "Annotations State", DataType.XML, None, "Annotations State", "ANNOTATIONS_FLY", None] ]]; -SEARCH_QUERY = [MANDATORY_ITEM_VERSION, True, True, "SEARCH_QUERY", "Used to store saved search queries", [ - [MANDATORY_ITEM_VERSION, "NAME", "General", "Name", DataType.VARCHAR, None, "Name", None, None], - [MANDATORY_ITEM_VERSION, "CRITERIA", "General", "Criteria", DataType.XML, None, "Criteria", None, None], - [MANDATORY_ITEM_VERSION, "XMLCOMMENTS", "Comments", "Comments List", DataType.XML, None, "Several comments can be added by different users", "COMMENTS_SAMPLE", None], - [MANDATORY_ITEM_VERSION, "ANNOTATIONS_STATE", "Comments", "Annotations State", DataType.XML, None, "Annotations State", "ANNOTATIONS_CHEMICAL", None] - ]]; - ## ## Sample Types - Non Materials ## diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/initializemasterdataminimum.py b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/initializemasterdataminimum.py index c2be900823e32d9589eef062899f6512b12d18db..fe2669761f80c3211950f8633bea2ceb6cd18177 100644 --- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/initializemasterdataminimum.py +++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/initializemasterdataminimum.py @@ -63,7 +63,6 @@ def initBasicMasterData(tr): ## Sample Types - Non Materials ## elnTypes.createSampleTypeWithProperties(tr, elnTypes.GENERAL_ELN_SETTINGS); - elnTypes.createSampleTypeWithProperties(tr, elnTypes.SEARCH_QUERY); elnTypes.createSampleTypeWithProperties(tr, elnTypes.EXPERIMENTAL_STEP); elnTypes.createSampleTypeWithProperties(tr, elnTypes.STORAGE_RACK); elnTypes.createSampleTypeWithProperties(tr, elnTypes.STORAGE_POSITION); 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 e8dd6a389c4772afb46a30dcfeb2ea0507e4c7b6..c487f60c0294ffed2d74778c0fbdb253c40c6bf1 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 @@ -701,28 +701,12 @@ function ServerFacade(openbisServer) { callbackFunction(error, result); }); } - - this.customELNASAPI = function(parameters, callackFunction) { - require([ "as/dto/service/id/CustomASServiceCode", "as/dto/service/CustomASServiceExecutionOptions" ], - function(CustomASServiceCode, CustomASServiceExecutionOptions) { - var id = new CustomASServiceCode("as-eln-lims-api"); - var options = new CustomASServiceExecutionOptions(); - - if(parameters) { - for(key in parameters) { - options.withParameter(key, parameters[key]); - } - } - - mainController.openbisV3.executeCustomASService(id, options).done(function(result) { - callackFunction(result); - }).fail(function(result) { - alert("Call failed to server: " + JSON.stringify(result)); - }); - }); - } - - this.createReportFromAggregationService = function(dataStoreCode, parameters, callbackFunction, service) { + + this.customELNASAPI = function(parameters, callbackFunction) { + this.customASService(parameters, callbackFunction, "as-eln-lims-api"); + } + + this.createReportFromAggregationService = function(dataStoreCode, parameters, callbackFunction, service) { if(!service) { service = "eln-lims-api"; } @@ -846,21 +830,39 @@ function ServerFacade(openbisServer) { // // New Advanced Search // - + + this.getSearchCriteriaAndFetchOptionsForDataSetSearch = function(advancedSearchCriteria, advancedFetchOptions, callback) { + var criteriaClass = 'as/dto/dataset/search/DataSetSearchCriteria'; + var fetchOptionsClass = 'as/dto/dataset/fetchoptions/DataSetFetchOptions'; + this.getSearchCriteriaAndFetchOptionsForEntitySearch(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass); + } + 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, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass, searchMethodName); } - + + this.getSearchCriteriaAndFetchOptionsForExperimentSearch = function(advancedSearchCriteria, advancedFetchOptions, callback) { + var criteriaClass = 'as/dto/experiment/search/ExperimentSearchCriteria'; + var fetchOptionsClass = 'as/dto/experiment/fetchoptions/ExperimentFetchOptions'; + this.getSearchCriteriaAndFetchOptionsForEntitySearch(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass); + } + 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, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass, searchMethodName); } - + + this.getSearchCriteriaAndFetchOptionsForSamplesSearch = function(advancedSearchCriteria, advancedFetchOptions, callback) { + var criteriaClass = 'as/dto/sample/search/SampleSearchCriteria'; + var fetchOptionsClass = 'as/dto/sample/fetchoptions/SampleFetchOptions'; + this.getSearchCriteriaAndFetchOptionsForEntitySearch(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass); + } + this.searchForSamplesAdvanced = function(advancedSearchCriteria, advancedFetchOptions, callback) { var criteriaClass = 'as/dto/sample/search/SampleSearchCriteria'; var fetchOptionsClass = 'as/dto/sample/fetchoptions/SampleFetchOptions'; @@ -881,8 +883,8 @@ function ServerFacade(openbisServer) { var searchMethodName = 'searchProjects'; this.searchForEntityAdvanced(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass, searchMethodName); } - - this.searchForEntityAdvanced = function(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass, searchMethodName) { + + this.getSearchCriteriaAndFetchOptionsForEntitySearch = function(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass) { require([criteriaClass, fetchOptionsClass, 'as/dto/common/search/DateObjectEqualToValue', @@ -1341,43 +1343,51 @@ function ServerFacade(openbisServer) { // // Fix For broken equals PART 1 - END // - - mainController.openbisV3[searchMethodName](searchCriteria, fetchOptions) - .done(function(apiResults) { - // - // Fix For broken equals PART 2 - // - var results = apiResults.objects; - var filteredResults = []; - if(hackFixForBrokenEquals.length > 0 && results) { - for(var rIdx = 0; rIdx < results.length; rIdx++) { - var result = results[rIdx]; - for(var fIdx = 0; fIdx < hackFixForBrokenEquals.length; fIdx++) { - if( result && - result.properties && - result.properties[hackFixForBrokenEquals[fIdx].propertyCode] === hackFixForBrokenEquals[fIdx].value) { - filteredResults.push(result); - } - } - } - } else { - filteredResults = results; - } - apiResults.objects = filteredResults; - // - // Fix For broken equals PART 2 - END - // - callback(apiResults); - }) - .fail(function(result) { - Util.showError("Call failed to server: " + JSON.stringify(result)); - }); + callback(searchCriteria, fetchOptions, hackFixForBrokenEquals); + } catch(exception) { Util.showError(exception.name + ": " + exception.message); } }); } - + + this.searchForEntityAdvanced = function(advancedSearchCriteria, advancedFetchOptions, callback, criteriaClass, fetchOptionsClass, searchMethodName) { + var searchFunction = function(searchCriteria, fetchOptions, hackFixForBrokenEquals) { + mainController.openbisV3[searchMethodName](searchCriteria, fetchOptions) + .done(function(apiResults) { + // + // Fix For broken equals PART 2 + // + var results = apiResults.objects; + var filteredResults = []; + if(hackFixForBrokenEquals.length > 0 && results) { + for(var rIdx = 0; rIdx < results.length; rIdx++) { + var result = results[rIdx]; + for(var fIdx = 0; fIdx < hackFixForBrokenEquals.length; fIdx++) { + if( result && + result.properties && + result.properties[hackFixForBrokenEquals[fIdx].propertyCode] === hackFixForBrokenEquals[fIdx].value) { + filteredResults.push(result); + } + } + } + } else { + filteredResults = results; + } + apiResults.objects = filteredResults; + // + // Fix For broken equals PART 2 - END + // + callback(apiResults); + }) + .fail(function(result) { + Util.showError("Call failed to server: " + JSON.stringify(result)); + }); + } + + this.getSearchCriteriaAndFetchOptionsForEntitySearch(advancedSearchCriteria, advancedFetchOptions, searchFunction, criteriaClass, fetchOptionsClass); + } + // // Search Samples // @@ -2013,16 +2023,15 @@ function ServerFacade(openbisServer) { // // Global Search // - this.searchGlobally = function(freeText, advancedFetchOptions, callbackFunction) - { - var _this = this; + + this.getSearchCriteriaAndFetchOptionsForGlobalSearch = function(freeText, advancedFetchOptions, callbackFunction) { require(['as/dto/global/search/GlobalSearchCriteria', 'as/dto/global/fetchoptions/GlobalSearchObjectFetchOptions'], function(GlobalSearchCriteria, GlobalSearchObjectFetchOptions){ var searchCriteria = new GlobalSearchCriteria(); searchCriteria.withText().thatContains(freeText.toLowerCase().trim()); searchCriteria.withOperator("AND"); - + var fetchOptions = new GlobalSearchObjectFetchOptions(); var sampleFetchOptions = fetchOptions.withSample(); sampleFetchOptions.withSpace(); @@ -2056,7 +2065,15 @@ function ServerFacade(openbisServer) { fetchOptions.from(advancedFetchOptions.from); fetchOptions.count(advancedFetchOptions.count); } - + + callbackFunction(searchCriteria, fetchOptions); + }); + } + + this.searchGlobally = function(freeText, advancedFetchOptions, callbackFunction) + { + this.getSearchCriteriaAndFetchOptionsForGlobalSearch(freeText, advancedFetchOptions, function(searchCriteria, fetchOptions) + { mainController.openbisV3.searchGlobally(searchCriteria, fetchOptions).done(function(results) { callbackFunction(results); }).fail(function(error) { @@ -2506,4 +2523,97 @@ function ServerFacade(openbisServer) { callbackFunction(false); }); } + + this.searchCustomASServices = function(code, callbackFunction) { + require(['as/dto/service/search/CustomASServiceSearchCriteria', 'as/dto/service/fetchoptions/CustomASServiceFetchOptions'], + function(CustomASServiceSearchCriteria, CustomASServiceFetchOptions) { + var searchCriteria = new CustomASServiceSearchCriteria(); + var fetchOptions = new CustomASServiceFetchOptions(); + searchCriteria.withCode().thatEquals(code); + mainController.openbisV3.searchCustomASServices(searchCriteria, fetchOptions).done(function(result) { + callbackFunction(result); + Â Â Â Â Â Â Â Â }).fail(function(result) { + Util.showError("Call failed to server: " + JSON.stringify(result)); + callbackFunction(false); + }); + } + ); + } + + // errorHandler: optional. if present, it is called instead of showing the error and the callbackFunction is not called + this.customASService = function(parameters, callbackFunction, serviceCode, errorHandler) { + require([ "as/dto/service/id/CustomASServiceCode", "as/dto/service/CustomASServiceExecutionOptions" ], + function(CustomASServiceCode, CustomASServiceExecutionOptions) { + var id = new CustomASServiceCode(serviceCode); + var options = new CustomASServiceExecutionOptions(); + + if(parameters) { + for(key in parameters) { + options.withParameter(key, parameters[key]); + } + } + + mainController.openbisV3.executeCustomASService(id, options).done(function(result) { + callbackFunction(result); + }).fail(function(result) { + if (errorHandler) { + errorHandler(result); + } else { + alert("Call failed to server: " + JSON.stringify(result)); + } + }); + }); + } + + // + // search-store Functions + // + + this.callSearchStoreService = function(parameters, callbackFunction) { + this.customASService(parameters, callbackFunction, 'search-store', function(errorResult) { + Util.showError("Call failed to server: " + JSON.stringify(errorResult)); + callbackFunction(false); + }); + } + + this.saveSearch = function(space, experiment, name, criteriaV3, fetchOptionsV3, criteriaEln, callbackFunction) { + var parameters = { + method: 'SAVE', + name: name, + searchCriteria: criteriaV3, + fetchOptions: fetchOptionsV3, + customData: { 'eln-lims-criteria': criteriaEln }, + spacePermId: space.permId.permId, + experimentPermId: experiment.permId.permId, + } + this.callSearchStoreService(parameters, callbackFunction); + } + + this.updateSearch = function(permId, criteriaV3, fetchOptionsV3, criteriaEln, callbackFunction) { + var parameters = { + method: 'UPDATE', + permId: permId, + searchCriteria: criteriaV3, + fetchOptions: fetchOptionsV3, + customData: { 'eln-lims-criteria': criteriaEln }, + } + this.callSearchStoreService(parameters, callbackFunction); + } + + this.loadSearches = function(callbackFunction) { + var parameters = { + method: 'LOAD', + } + this.callSearchStoreService(parameters, callbackFunction); + } + + this.deleteSearch = function(permId, reason, callbackFunction) { + parameters = { + method: 'DELETE', + permId: permId, + reason: reason, + } + this.callSearchStoreService(parameters, callbackFunction); + } + } 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 1b08ef8f11236de7f2248b17025f8cc3ea9a2cba..09d7f2f9b9aac9133bb8d2ccc2ab8313e42d4e8f 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 @@ -21,8 +21,15 @@ function AdvancedSearchController(mainController, forceSearch) { this.init = function(views) { var _this = this; - this._loadSavedSearches(function() { - _this._advancedSearchView.repaint(views); + _this._searchStoreAvailable(function(searchStoreAvailable) { + _this._advancedSearchModel.searchStoreAvailable = searchStoreAvailable; + if (searchStoreAvailable) { + _this._loadSavedSearches(function() { + _this._advancedSearchView.repaint(views); + }); + } else { + _this._advancedSearchView.repaint(views); + } }); } @@ -220,10 +227,44 @@ function AdvancedSearchController(mainController, forceSearch) { } } + this._getSearchCriteriaV3 = function(callback) { + var criteriaToSend = $.extend(true, {}, this._advancedSearchModel.criteria); + switch(criteriaToSend.entityKind) { + case "ALL": + var freeText = ""; + for(var ruleId in criteriaToSend.rules) { + if(criteriaToSend.rules[ruleId].value) { + freeText += " " + criteriaToSend.rules[ruleId].value; + } + } + mainController.serverFacade.getSearchCriteriaAndFetchOptionsForGlobalSearch(freeText, {}, callback); + break; + case "SAMPLE": + mainController.serverFacade.getSearchCriteriaAndFetchOptionsForSamplesSearch(criteriaToSend, {}, callback); + break; + case "EXPERIMENT": + mainController.serverFacade.getSearchCriteriaAndFetchOptionsForExperimentSearch(criteriaToSend, {}, callback); + break; + case "DATASET": + mainController.serverFacade.getSearchCriteriaAndFetchOptionsForDataSetSearch(criteriaToSend, {}, callback); + break; + } + } + // // query loading / saving // + this._searchStoreAvailable = function(callback) { + this._mainController.serverFacade.searchCustomASServices('search-store', function(result) { + if (result != null && result.objects.length > 0) { + callback(true); + } else { + callback(false); + } + }) + } + this.selectSavedSearch = function(selcetedSavedSearchIndex) { var savedSearch = this._advancedSearchModel.savedSearches[selcetedSavedSearchIndex]; this._advancedSearchModel.selcetedSavedSearchIndex = selcetedSavedSearchIndex; @@ -236,22 +277,18 @@ function AdvancedSearchController(mainController, forceSearch) { // params.experiment this.saveNewSample = function(params, callback) { var _this = this; - var criteria = _this._getSerializedCriteria(); this._ensureProjectAndExperiment(params.experiment, function(experiment) { _this._doIfAdmin(experiment, function() { - _this._mainController.serverFacade.createSample('SEARCH_QUERY', experiment, { - NAME: params.name, - CRITERIA: criteria, - }, function(result) { - var permId = result[0].permId; - _this._mainController.serverFacade.getSamples([permId], function(result) { - if (result[permId]) { - var savedSearch = _this._sampleToSavedSearch(result[permId]); - _this._advancedSearchModel.savedSearches.push(savedSearch); - _this.selectSavedSearch(_this._advancedSearchModel.savedSearches.length - 1); - } - callback(); + _this._getSearchCriteriaV3(function(criteriaV3, fetchOptionsV3) { + var criteriaEln = _this._advancedSearchModel.criteria; + var space = experiment.project.space; + _this._mainController.serverFacade.saveSearch(space, experiment, params.name, criteriaV3, fetchOptionsV3, criteriaEln, function(sample) { + Util.showSuccess('Search saved.'); + var savedSearch = _this._sampleToSavedSearch(sample); + _this._advancedSearchModel.savedSearches.unshift(savedSearch); + _this.selectSavedSearch(0); + callback(); }); }); }); @@ -260,41 +297,39 @@ function AdvancedSearchController(mainController, forceSearch) { this.updateSelectedSample = function(callback) { var _this = this; - var criteria = _this._getSerializedCriteria(); var savedSearch = _this._advancedSearchModel.savedSearches[_this._advancedSearchModel.selcetedSavedSearchIndex]; _this._doIfAdmin(savedSearch.sample.experiment, function() { - _this._mainController.serverFacade.updateSample({ - permId: savedSearch.sample.permId.permId, - properties: { - CRITERIA: criteria, - }, - }, function(success) { - if (success) { - Util.showSuccess('Search updated.'); - savedSearch.criteria = _this._clone(_this._advancedSearchModel.criteria); - } - callback(); + + _this._getSearchCriteriaV3(function(criteriaV3, fetchOptionsV3) { + var criteriaEln = _this._advancedSearchModel.criteria; + var selcetedSavedSearchIndex = _this._advancedSearchModel.selcetedSavedSearchIndex; + var permId = _this._advancedSearchModel.savedSearches[selcetedSavedSearchIndex].sample.permId.permId; + _this._mainController.serverFacade.updateSearch(permId, criteriaV3, fetchOptionsV3, criteriaEln, function(result){ + if (result) { + Util.showSuccess('Search updated.'); + savedSearch.criteria = _this._clone(_this._advancedSearchModel.criteria); + } + callback(); + }); }); }); } this.delete = function(selcetedSavedSearchIndex, callback) { var _this = this; - var savedSearch = _this._advancedSearchModel.savedSearches[selcetedSavedSearchIndex]; - this._mainController.serverFacade.deleteSamples( - [savedSearch.sample.permId.permId], - 'Search query deletion by user', - function(deletionId) { - if (deletionId) { - _this._advancedSearchModel.selcetedSavedSearchIndex = -1; - Util.showSuccess('Search deleted.'); - _this._loadSavedSearches(function() { - _this._advancedSearchView.repaintContent(); - }); - } - callback(); + var selcetedSavedSearchIndex = _this._advancedSearchModel.selcetedSavedSearchIndex; + var permId = _this._advancedSearchModel.savedSearches[selcetedSavedSearchIndex].sample.permId.permId; + var reason = 'Search query deletion by user'; + this._mainController.serverFacade.deleteSearch(permId, reason, function(deletionId) { + if (deletionId) { + _this._advancedSearchModel.selcetedSavedSearchIndex = -1; + Util.showSuccess('Search deleted.'); + _this._loadSavedSearches(function() { + _this._advancedSearchView.repaintContent(); + }); } - ); + callback(); + }); } this.clearSelection = function() { @@ -307,7 +342,7 @@ function AdvancedSearchController(mainController, forceSearch) { this._mainController.serverFacade.searchSamplesV3('SEARCH_QUERY', function(result) { _this._advancedSearchModel.savedSearches = []; if(result != null && result.objects != null) { - var samples = _this._sortSavedSearchSamples(result.objects); + var samples = _this._sortSearchSamples(result.objects); for (var i=0; i<samples.length; i++) { _this._advancedSearchModel.savedSearches.push(_this._sampleToSavedSearch(samples[i])); } @@ -318,7 +353,7 @@ function AdvancedSearchController(mainController, forceSearch) { // puts own samples on top // samples are assumed to already be sorted by date - this._sortSavedSearchSamples = function(samples) { + this._sortSearchSamples = function(samples) { var ownSamples = []; var otherSamples = []; for (var i=0; i<samples.length; i++) { @@ -331,6 +366,21 @@ function AdvancedSearchController(mainController, forceSearch) { return ownSamples.concat(otherSamples); } + // puts own samples on top + // samples are assumed to already be sorted by date + this._sortSearches = function(searches) { + var ownSearches = []; + var otherSearches = []; + for (var i=0; i<searches.length; i++) { + if (searches[i].sample.registrator.userId == this._mainController.serverFacade.getUserId()) { + ownSearches.push(searches[i]); + } else { + otherSearches.push(searches[i]); + } + } + return ownSearches.concat(otherSearches); + } + this._ensureProjectAndExperiment = function(experiment, callback) { var _this = this; if (experiment.defaultDummyExperiment) { @@ -383,14 +433,10 @@ function AdvancedSearchController(mainController, forceSearch) { return { sample: sample, name: sample.properties.NAME, - criteria: JSON.parse(atob(sample.properties.CRITERIA.replace('<criteria>', '').replace('</criteria>', ''))), + criteria: JSON.parse(sample.properties.CUSTOM_DATA.replace('<xml><![CDATA[', '').replace(']]></xml>', ''))['eln-lims-criteria'], }; } - this._getSerializedCriteria = function() { - return '<criteria>' + btoa(JSON.stringify(this._advancedSearchModel.criteria)) + '</criteria>'; - } - this._doIfAdmin = function(experiment, action) { var _this = this; _this._mainController.getUserRole({ @@ -409,4 +455,5 @@ function AdvancedSearchController(mainController, forceSearch) { this._clone = function(object) { return JSON.parse(JSON.stringify(object)); } + } diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchModel.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchModel.js index e75a6608e04d9a94bc05834e8e5753bbc28c2a51..a58e7755519ebb6a8cb2bd137a1ea90bf7c30f2a 100644 --- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchModel.js +++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/AdvancedSearch/AdvancedSearchModel.js @@ -25,6 +25,7 @@ function AdvancedSearchModel(forceSearch) { } this.savedSearches = []; // [{ sample: v3Sample, name: "name", criteria: { see this.criteria }}, ...] this.selcetedSavedSearchIndex = -1; + this.searchStoreAvailable = null; if(typeof forceSearch === 'object') { this.criteria = forceSearch; 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 15505da7ca0ef64fd898aadeb9754f94877147e6..53e2f7571b1397dc277b816df95417aed0157176 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 @@ -161,6 +161,10 @@ function AdvancedSearchView(advancedSearchController, advancedSearchModel) { var _this = this; $container.empty(); + if (this._advancedSearchModel.searchStoreAvailable != true) { + return; + } + var savedSearchOptions = [{ label: 'load a saved search', value: -1, diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/4 b/openbis_standard_technologies/dist/core-plugins/eln-lims/4 deleted file mode 120000 index 56a6051ca2b02b04ef92d5150c9ef600403cb1de..0000000000000000000000000000000000000000 --- a/openbis_standard_technologies/dist/core-plugins/eln-lims/4 +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/openbis_standard_technologies/dist/core-plugins/search-store/1/as/initialize-master-data.py b/openbis_standard_technologies/dist/core-plugins/search-store/1/as/initialize-master-data.py new file mode 100644 index 0000000000000000000000000000000000000000..bcb50b7754ec8533b9f81ed676d76b3a2cb462f5 --- /dev/null +++ b/openbis_standard_technologies/dist/core-plugins/search-store/1/as/initialize-master-data.py @@ -0,0 +1,67 @@ +''' +@copyright: +2016 ETH Zuerich, SIS + +@license: +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +''' + +import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.DataType as DataType + + +SAMPLE_TYPE_SEARCH_QUERY = "SEARCH_QUERY" +# we use XML to store the properties to avoid indexing of the fields +PROPERTY_TYPES = [ + { + 'code': 'NAME', + 'dataType': DataType.VARCHAR, + 'label': 'Name', + 'mandatory': True, + 'description': 'Human readable name' + }, + { + 'code': 'SEARCH_CRITERIA', + 'dataType': DataType.XML, + 'label': 'Search criteria', + 'mandatory': True, + 'description': 'V3 API search criteria' + }, + { + 'code': "FETCH_OPTIONS", + 'dataType': DataType.XML, + 'label': 'Fetch options', + 'mandatory': False, + 'description': 'V3 API fetch options' + }, + { + 'code': "CUSTOM_DATA", + 'dataType': DataType.XML, + 'label': 'Custom data', + 'mandatory': False, + 'description': 'Additional data in custom format' + } + ] + + +tr = service.transaction() + +sample_type = tr.getOrCreateNewSampleType(SAMPLE_TYPE_SEARCH_QUERY) +sample_type.setGeneratedCodePrefix("Q") + +for propert_type_def in PROPERTY_TYPES: + property_type = tr.getOrCreateNewPropertyType(propert_type_def['code'], propert_type_def['dataType']) + property_type.setLabel(propert_type_def['label']) + property_type.setDescription(propert_type_def['description']) + assignment = tr.assignPropertyType(sample_type, property_type) + assignment.setMandatory(propert_type_def['mandatory']) + assignment.setShownEdit(True) diff --git a/openbis_standard_technologies/dist/core-plugins/search-store/1/as/services/search-store/README.md b/openbis_standard_technologies/dist/core-plugins/search-store/1/as/services/search-store/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5da934c5ea024a96ab24832788bc037e8c2f54fa --- /dev/null +++ b/openbis_standard_technologies/dist/core-plugins/search-store/1/as/services/search-store/README.md @@ -0,0 +1,17 @@ +# openBIS search store + +## Description + +This plugin provides an API for storing searches in the form of V3 API +search criteria and fetch options. + +## Masterdata + +The SEARCH_QUERY sample type is created to store the search criteria, +fetch options, name and custom data. To avoid indexing, the search +criteria, fetch options and custom data are stored as XML fields. + +## Service + +The service provices methods to save, update, load and delete the +searches. diff --git a/openbis_standard_technologies/dist/core-plugins/search-store/1/as/services/search-store/plugin.properties b/openbis_standard_technologies/dist/core-plugins/search-store/1/as/services/search-store/plugin.properties new file mode 100644 index 0000000000000000000000000000000000000000..6d9f56538a8a7fd19a065cacb5b24e83f666fa40 --- /dev/null +++ b/openbis_standard_technologies/dist/core-plugins/search-store/1/as/services/search-store/plugin.properties @@ -0,0 +1,2 @@ +class = ch.ethz.sis.openbis.generic.server.asapi.v3.helper.service.JythonBasedCustomASServiceExecutor +script-path = search-store.py diff --git a/openbis_standard_technologies/dist/core-plugins/search-store/1/as/services/search-store/search-store.py b/openbis_standard_technologies/dist/core-plugins/search-store/1/as/services/search-store/search-store.py new file mode 100644 index 0000000000000000000000000000000000000000..6b7556ca932d54b809f54118997dc6c452347840 --- /dev/null +++ b/openbis_standard_technologies/dist/core-plugins/search-store/1/as/services/search-store/search-store.py @@ -0,0 +1,164 @@ +# +# Copyright 2014 ETH Zuerich, Scientific IT Services +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import json +from ch.ethz.sis.openbis.generic.server.sharedapi.v3.json import GenericObjectMapper +from ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.create import SampleCreation +from ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id import EntityTypePermId +from ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id import ExperimentPermId +from ch.ethz.sis.openbis.generic.asapi.v3.dto.space.id import SpacePermId +from ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id import ProjectPermId +from ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.search import SampleSearchCriteria +from ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions import SampleFetchOptions +from ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id import SamplePermId +from ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.update import SampleUpdate +from ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.delete import SampleDeletionOptions + + +SAMPLE_TYPE = 'SEARCH_QUERY' +PROP_NAME = 'NAME' +PROP_SEARCH_CRITERIA = 'SEARCH_CRITERIA' +PROP_FETCH_OPTIONS = 'FETCH_OPTIONS' +PROP_CUSTOM_DATA = 'CUSTOM_DATA' + +PREFIX_XML = '<xml><![CDATA[' +POSTFIX_XML = ']]></xml>' + + +def process(context, parameters): + """ Entry point for all methods. + :param parameters['method']: SAVE, UPDATE, LOAD or DELETE + see specific functions for more parameters. + """ + + method = parameters['method'] + + if method == 'SAVE': + return save(context, parameters) + elif method == 'UPDATE': + return update(context, parameters) + elif method == 'LOAD': + return load(context, parameters) + elif method == 'DELETE': + return delete(context, parameters) + return None + + +def save(context, parameters): + """ Saves a search query in a sample. + :param parameters['spacePermId']: (optional) permId of the space in which to save the search + :param parameters['projectPermId']: (optional) permId of the project in which to save the search + :param parameters['experimentPermId']: (optional) permId of the experiment in which to save the search + :param parameters['name']: human readable name of the search + :param parameters['searchCriteria']: V3 search criteria + :param parameters['fetchOptions']: (optional) V3 fetch options + :param parameters['customData']: (optional) additional data in JSON format + """ + result = _save(context, parameters) + if len(result) > 0 and result[0].permId is not None: + permId = SamplePermId(result[0].permId) + fetchOptions = _getSampleFetchOptions() + result = context.applicationService.getSamples(context.sessionToken, [permId], fetchOptions) + return result[permId] + else: + return result + + +def update(context, parameters): + """ Updates an existing search. + :param parameters['permId']: permId of the search sample to update + :param parameters['name']: (optional) human readable name of the search + :param parameters['searchCriteria']: (optional) V3 search crieria + :param parameters['fetchOptions']: (optional) V3 fetch options + :param parameters['customData']: (optional) additional data in JSON format + """ + sampleUpdate = SampleUpdate() + sampleUpdate.setSampleId(SamplePermId(parameters['permId'])) + if 'name' in parameters: + sampleUpdate.setProperty(PROP_NAME, _serialize(parameters['name'])) + if 'searchCriteria' in parameters: + sampleUpdate.setProperty(PROP_SEARCH_CRITERIA, _serialize(parameters['searchCriteria'])) + if 'fetchOptions' in parameters: + sampleUpdate.setProperty(PROP_FETCH_OPTIONS, _serialize(parameters['fetchOptions'])) + if 'customData' in parameters: + sampleUpdate.setProperty(PROP_CUSTOM_DATA, _serialize(parameters['customData'])) + + context.applicationService.updateSamples(context.sessionToken, [sampleUpdate]) + return True + + +def load(context, parameters): + """ Loads all stores query samples. + """ + searchCriteria = SampleSearchCriteria() + searchCriteria.withType().withCode().thatEquals(SAMPLE_TYPE) + fetchOptions = _getSampleFetchOptions() + result = context.applicationService.searchSamples(context.sessionToken, searchCriteria, fetchOptions) + return result + + +def delete(context, parameters): + """ Deletes a stored search. + :param parameters['permId']: permId of the search to delete + :param parameters['reason']: reason for deletion + """ + permId = SamplePermId(parameters['permId']) + reason = parameters['reason'] + deletionOptions = SampleDeletionOptions() + deletionOptions.setReason(reason) + result = context.applicationService.deleteSamples(context.sessionToken, [permId], deletionOptions) + return result + + +def _save(context, parameters): + sampleCreation = SampleCreation() + sampleCreation.setAutoGeneratedCode(True) + sampleCreation.setTypeId(EntityTypePermId(SAMPLE_TYPE)) + if 'experimentPermId' in parameters: + sampleCreation.setExperimentId(ExperimentPermId(parameters['experimentPermId'])) + if 'spacePermId' in parameters: + sampleCreation.setSpaceId(SpacePermId(parameters['spacePermId'])) + if 'projectPermId' in parameters: + sampleCreation.setProjectId(ProjectPermId(parameters['projectPermId'])) + + sampleCreation.setProperty(PROP_NAME, parameters['name']) + + searchCriteriaValue = _serialize(parameters['searchCriteria']) + sampleCreation.setProperty(PROP_SEARCH_CRITERIA, searchCriteriaValue) + + if 'fetchOptions' in parameters: + fetchOptionsValue = _serialize(parameters['fetchOptions']) + sampleCreation.setProperty(PROP_FETCH_OPTIONS, fetchOptionsValue) + + if 'customData' in parameters: + customDataValue = _serialize(parameters['customData']) + sampleCreation.setProperty(PROP_CUSTOM_DATA, customDataValue) + + return context.applicationService.createSamples(context.sessionToken, [sampleCreation]) + + +def _getSampleFetchOptions(): + fetchOptions = SampleFetchOptions() + fetchOptions.withProperties() + fetchOptions.withExperiment().withProject().withSpace() + fetchOptions.withRegistrator() + fetchOptions.sortBy().modificationDate().desc() + return fetchOptions + + +def _serialize(obj): + jsonString = GenericObjectMapper().writer().writeValueAsString(obj) + return PREFIX_XML + jsonString + POSTFIX_XML