Commit d5c6648c authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge remote-tracking branch 'origin/master' into...

Merge remote-tracking branch 'origin/master' into 1529-introduce-uniform-checkstyle-validation-as-gitlab-job
parents d17d39dc 46fee41d
Pipeline #46983 failed with stage
in 12 minutes and 29 seconds
minerva (16.1.0~alpha.0) stable; urgency=medium
* Small improvement: API provides information about modifier type (#1085)
* Small improvement: map file for JavaScript is properly referenced (#1545)
* Bug fix: api endpoints were exposed without 'api' prefix
* Bug fix: anonymous user could upload file using API
* Bug fix: when passing JSON in patch/post methods contentType was not
checked
-- Piotr Gawron <piotr.gawron@uni.lu> Thu, 9 Sep 2021 13:00:00 +0200
minerva (16.0.0~beta.2) stable; urgency=medium
* Small improvement: backgrounds are separated from general overlays (#1532)
* Small improvement: layout of pin popup window is slitghly improved (#1493)
* Small improvement: search results are grouped by submap with hits (#1505)
* Bug fix: correct background order for old projects restored (#1533)
* Bug fix: search chemicals by target returned chemicals not bounded by
disease (#1535)
* Bug fix: problem with export map with submaps fixed (#1540)
* Bug fix: clear does not show warning about missing disease ID (#1541)
* Bug fix: removing user removed backgrounds in projects created by user
(#1527)
* Bug fix: removing background did not remove images from server (#1526)
* Bug fix: two genomic data overlay with two different reference genomes
caused issue (#1546)
* Bug fix: search results were limited to 10 elements
-- Piotr Gawron <piotr.gawron@uni.lu> Thu, 9 Sep 2021 11:00:00 +0200
minerva (16.0.0~beta.1) stable; urgency=medium
* Backward incompatibility: layout parameter in minerva url is not supported
anymore
......
......@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import javax.xml.bind.annotation.XmlRootElement;
......@@ -329,4 +330,12 @@ public class Chemical implements Serializable, TargettingStructure {
}
}
public boolean containsTarget(MiriamData miriamTarget) {
boolean result = false;
for (Target target : getTargets()) {
result |= target.getGenes().contains(new MiriamData(miriamTarget.getDataType(), miriamTarget.getResource()));
}
return result;
}
}
......@@ -9,6 +9,10 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lcsb.mapviewer.annotation.data.serializer.MeSHSerializer;
/**
* This class represents <a href="http://www.nlm.nih.gov/cgi/mesh//">MeSH</a>
* object.
......@@ -17,6 +21,7 @@ import org.apache.logging.log4j.Logger;
*
*/
@XmlRootElement
@JsonSerialize(using = MeSHSerializer.class)
public class MeSH implements Serializable {
/**
......
package lcsb.mapviewer.annotation.data.serializer;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lcsb.mapviewer.annotation.data.MeSH;
public class MeSHSerializer extends JsonSerializer<MeSH> {
@Override
public void serialize(final MeSH mesh, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeStringField("name", mesh.getName());
gen.writeStringField("id", mesh.getMeSHId());
gen.writeStringField("description", mesh.getDescription());
gen.writeObjectField("synonyms", mesh.getSynonyms());
gen.writeEndObject();
}
}
\ No newline at end of file
......@@ -43,7 +43,7 @@ public class PubmedParser extends CachableInterface implements IExternalService
/**
* Version of the remote API that is supported by this connecting class.
*/
static final String SUPPORTED_VERSION = "6.5";
static final String SUPPORTED_VERSION = "6.6";
static final String API_URL = "https://www.ebi.ac.uk/europepmc/webservices/rest/";
/**
* Length of {@link #PUBMED_PREFIX} string.
......
......@@ -2,7 +2,15 @@ package lcsb.mapviewer.annotation.services.dapi;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -14,10 +22,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import lcsb.mapviewer.annotation.data.Chemical;
import lcsb.mapviewer.annotation.data.Target;
import lcsb.mapviewer.annotation.services.dapi.dto.*;
import lcsb.mapviewer.annotation.services.dapi.dto.ChemicalEntityDto;
import lcsb.mapviewer.annotation.services.dapi.dto.ChemicalEntityDtoConverter;
import lcsb.mapviewer.annotation.services.dapi.dto.ListChemicalEntityDto;
import lcsb.mapviewer.common.exception.InvalidArgumentException;
import lcsb.mapviewer.model.Project;
import lcsb.mapviewer.model.map.*;
import lcsb.mapviewer.model.map.BioEntity;
import lcsb.mapviewer.model.map.MiriamData;
import lcsb.mapviewer.model.map.MiriamType;
import lcsb.mapviewer.model.map.model.ModelData;
import lcsb.mapviewer.model.map.model.ModelSubmodelConnection;
......@@ -137,8 +149,10 @@ public class ChemicalParser {
ListChemicalEntityDto dto = objectMapper.readValue(content, ListChemicalEntityDto.class);
List<Chemical> chemicals = fetchChemicals(dto, disease);
for (Chemical drug : chemicals) {
result.put(drug.getChemicalId(), drug);
for (Chemical chemical : chemicals) {
if (chemical.containsTarget(target)) {
result.put(chemical.getChemicalId(), chemical);
}
}
}
return new ArrayList<>(result.values());
......@@ -183,8 +197,10 @@ public class ChemicalParser {
}
Set<String> names = new HashSet<>();
for (MiriamData hgncSymbol : hgncSymbols) {
// fetching all chemicals for big map is very memory exhaustive, therefore do it
// step by step to prevent storing everything in the memory at single point
// fetching all chemicals for big map is very memory exhaustive, therefore
// do it
// step by step to prevent storing everything in the memory at single
// point
List<Chemical> chemicals = getChemicalListByTarget(hgncSymbol, diseaseMiriam);
for (Chemical chemical : chemicals) {
names.add(chemical.getChemicalName());
......
......@@ -2,6 +2,7 @@ package lcsb.mapviewer.annotation.services.dapi;
import java.util.List;
import lcsb.mapviewer.annotation.services.dapi.dto.DapiDatabase;
import lcsb.mapviewer.annotation.services.dapi.dto.ReleaseDto;
import lcsb.mapviewer.annotation.services.dapi.dto.UserDto;
......@@ -20,7 +21,7 @@ public interface DapiConnector {
void resetConnection();
List<String> getDatabases() throws DapiConnectionException;
List<DapiDatabase> getDatabases() throws DapiConnectionException;
List<ReleaseDto> getReleases(String database) throws DapiConnectionException;
......
......@@ -32,6 +32,7 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import lcsb.mapviewer.annotation.cache.CachableInterface;
import lcsb.mapviewer.annotation.services.dapi.dto.DapiDatabase;
import lcsb.mapviewer.annotation.services.dapi.dto.ListReleaseDto;
import lcsb.mapviewer.annotation.services.dapi.dto.ReleaseDto;
import lcsb.mapviewer.annotation.services.dapi.dto.UserDto;
......@@ -237,9 +238,9 @@ public class DapiConnectorImpl extends CachableInterface implements DapiConnecto
}
@Override
public List<String> getDatabases() throws DapiConnectionException {
public List<DapiDatabase> getDatabases() throws DapiConnectionException {
try {
List<String> result = new ArrayList<>();
List<DapiDatabase> result = new ArrayList<>();
String url = DAPI_BASE_URL + "database/";
String content = getWebPageDownloader().getFromNetwork(url);
JsonArray array = new JsonParser()
......@@ -249,7 +250,7 @@ public class DapiConnectorImpl extends CachableInterface implements DapiConnecto
.getAsJsonArray();
for (int i = 0; i < array.size(); i++) {
result.add(array.get(i).getAsJsonObject().get("name").getAsString());
result.add(new DapiDatabase(array.get(i).getAsJsonObject().get("name").getAsString()));
}
return result;
} catch (Exception e) {
......
package lcsb.mapviewer.annotation.services.dapi.dto;
public class DapiDatabase {
public String name;
public DapiDatabase(String name) {
this.name = name;
}
}
......@@ -30,7 +30,7 @@
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
......
......@@ -5,9 +5,9 @@
"main": "minerva.js",
"scripts": {
"build:css": "node scripts/build-css.js",
"build:js": "browserify --debug --standalone minerva src/main/js/minerva.js | exorcist dist/minerva.js.map > dist/minerva.js ",
"build-browser-check:js": "browserify --debug --standalone BrowserCheck src/main/js/BrowserCheck.js | exorcist dist/BrowserCheck.js.map > dist/BrowserCheck.js ",
"//": "rm -rf dist & rmdir /q /s dist & mkdir dist & browserify --debug --standalone minerva src/main/js/minerva.js | exorcist dist/minerva.js.map > dist/minerva.js & uglifyjs --compress --mangle --in-source-map dist/minerva.js.map --source-map-include-sources --source-map dist/minerva.min.js.map -o dist/minerva.min.js dist/minerva.js",
"build:js": "browserify --debug --standalone minerva src/main/js/minerva.js | exorcist dist/minerva.js.map --url 'minerva.js.map.xhtml?ln=js' > dist/minerva.js ",
"build-browser-check:js": "browserify --debug --standalone BrowserCheck src/main/js/BrowserCheck.js | exorcist dist/BrowserCheck.js.map --url 'BrowserCheck.js.map.xhtml?ln=js' > dist/BrowserCheck.js ",
"//": "rm -rf dist & rmdir /q /s dist & mkdir dist & browserify --debug --standalone minerva src/main/js/minerva.js | exorcist dist/minerva.js.map --url 'minerva.js.map.xhtml?ln=js' > dist/minerva.js & uglifyjs --compress --mangle --in-source-map dist/minerva.js.map --source-map-include-sources --source-map dist/minerva.min.js.map -o dist/minerva.min.js dist/minerva.js",
"build-deploy": "npm run build && npm run deploy",
"build": "npm run clean && npm run build:css && npm run build:js && npm run build-browser-check:js",
"clean": "node scripts/clean.js",
......
......@@ -124,16 +124,16 @@ GenericSearchPanel.prototype.createTableElement = function (element, icon) {
var result = document.createElement("div");
var table = document.createElement("table");
var expandStyle = "fa-eye";
var headerDiv;
var label = "";
if (element.getModelId() !== self.getMap().getId()) {
headerDiv = guiUtils.createSubMapLink({
label: "Submap: ",
mapId: element.getModelId()
});
label = "Submap: ";
} else {
headerDiv = document.createElement("div");
$(headerDiv).css("height", "21px");
label = "Top map: ";
}
var headerDiv = guiUtils.createSubMapLink({
label: label + "("+element.getBioEntities().length + " hits): ",
mapId: element.getModelId()
});
$(headerDiv).css("padding", "5px");
$(table).hide();
result.appendChild(headerDiv);
......@@ -189,13 +189,7 @@ GenericSearchPanel.prototype.addResultTab = function (query, elements) {
groupsByMap[element.getModelId()].addBioEntity(element);
}
}
return AbstractDbPanel.prototype.addResultTab.call(this, query, groups).then(function () {
var contentElement = self.getControlElement(PanelControlElementType.SEARCH_RESULTS_CONTENT_TAB);
var links = $(".table div>a.minerva-toggle-hide-show", contentElement);
if (links.length > 0) {
links[0].onclick();
}
});
return AbstractDbPanel.prototype.addResultTab.call(this, query, groups);
}
/**
......
......@@ -114,6 +114,27 @@ OverlayPanel.prototype.constructor = OverlayPanel;
* @private
*/
OverlayPanel.prototype._createOverlayPanelGui = function () {
var backgroundsDiv = Functions.createElement({
type: "div",
name: "backgroundsOverlays",
className: "searchPanel"
});
this.getElement().appendChild(backgroundsDiv);
var backgroundsTitle = Functions.createElement({
type: "h5",
content: "BACKGROUNDS:"
});
backgroundsDiv.appendChild(backgroundsTitle);
var backgroundsTableDiv = Functions.createElement({
type: "table",
name: "backgroundsTab",
className: "table table-bordered",
style: "width:100%"
});
backgroundsDiv.appendChild(backgroundsTableDiv);
var generalOverlaysDiv = Functions.createElement({
type: "div",
name: "generalOverlays",
......@@ -338,8 +359,6 @@ OverlayPanel.prototype.createBackgroundRow = function (background, checked) {
result.appendChild(viewTd);
var dataTd = document.createElement("td");
result.appendChild(dataTd);
result.title = background.getDescription();
return result;
};
......@@ -572,13 +591,25 @@ OverlayPanel.prototype.refresh = function (showDefault) {
} else {
customOverlays.push(overlay);
}
}
var table = self.getControlElement(PanelControlElementType.OVERLAY_GENERAL_OVERLAY_TABLE);
table.appendChild(self.createTableHeader());
var table = $("[name='backgroundsTab']", self.getElement())[0];
table.innerHTML = "<thead><tr><th>Name</th><th>View</th></tr></thead>";
var body = document.createElement("tbody");
table.appendChild(body);
for (i = 0; i < backgrounds.length; i++) {
var background = backgrounds[i];
body.appendChild(self.createBackgroundRow(background, background === selectedBackground));
}
table = self.getControlElement(PanelControlElementType.OVERLAY_GENERAL_OVERLAY_TABLE);
table.appendChild(self.createTableHeader());
body = document.createElement("tbody");
table.appendChild(body);
generalOverlays.sort(function (o1, o2) {
var val1 = o1.getId();
var val2 = o2.getId();
......@@ -594,14 +625,15 @@ OverlayPanel.prototype.refresh = function (showDefault) {
}
return 0;
});
for (i = 0; i < backgrounds.length; i++) {
var background = backgrounds[i];
body.appendChild(self.createBackgroundRow(background, background === selectedBackground));
}
for (i = 0; i < generalOverlays.length; i++) {
overlay = generalOverlays[i];
body.appendChild(self.createOverlayRow(overlay, selectedOverlay[overlay.getId()], false));
}
if (generalOverlays.length > 0) {
$(table.parentNode).show();
} else {
$(table.parentNode).hide();
}
var title = self.getControlElement(PanelControlElementType.OVERLAY_CUSTOM_OVERLAY_TITLE);
var addButton = $("[name='addOverlay']", self.getElement());
......
......@@ -47,7 +47,9 @@ ChemicalDbOverlay.prototype.getElementsByQueryFromServer = function (param) {
if (self.getMap().getProject().getDisease() !== undefined && self.getMap().getProject().getDisease() !== null) {
return ServerConnector.getChemicalsByQuery(param);
} else {
GuiConnector.warn("Cannot search for chemicals in a project without defined disease.");
if (param.query !== "") {
GuiConnector.warn("Cannot search for chemicals in a project without defined disease.");
}
return Promise.resolve([]);
}
};
......
......@@ -464,11 +464,11 @@ AbstractInfoWindow.prototype._createTargetInfoDiv = function (params) {
result.appendChild(titleElement);
if (overlay.allowGeneralSearch()) {
var checkboxDiv = document.createElement("div");
checkboxDiv.style.textAlign = "center";
var showAllButton = document.createElement("button");
var hideAllButton = document.createElement("button");
var checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = self.isOverlayFullView(overlay.getName());
checkbox.onclick = function () {
var toggleAll = function (show) {
var ie = new IdentifiedElement(self.alias);
result.removeChild(table);
var messageImg = Functions.createElement({
......@@ -476,20 +476,42 @@ AbstractInfoWindow.prototype._createTargetInfoDiv = function (params) {
src: 'resources/images/icons/ajax-loader.gif'
});
result.appendChild(messageImg);
return overlay.getDetailDataByIdentifiedElement(ie, this.checked).then(function (data) {
return overlay.getDetailDataByIdentifiedElement(ie, show).then(function (data) {
table = self._createTableForTargetDiv(data, overlay);
result.appendChild(table);
}).finally(function () {
result.removeChild(messageImg);
if (show) {
$(showAllButton).hide();
$(hideAllButton).show();
} else {
$(hideAllButton).hide();
$(showAllButton).show();
}
})
};
checkboxDiv.appendChild(checkbox);
showAllButton.style.display = "inline-block";
showAllButton.innerHTML = "Click to show all " + overlay.getName() + "s for ths element";
showAllButton.onclick = function () {
toggleAll(true);
}
checkboxDiv.appendChild(showAllButton);
hideAllButton.style.display = "inline-block";
hideAllButton.innerHTML = "Click to hide all " + overlay.getName() + "s for ths element";
hideAllButton.onclick = function () {
toggleAll(false);
}
checkboxDiv.appendChild(hideAllButton);
if (self.isOverlayFullView(overlay.getName())) {
$(showAllButton).hide();
} else {
$(hideAllButton).hide();
}
var description = document.createElement("div");
description.style.display = "inline-block";
description.innerHTML = "Show all";
checkboxDiv.appendChild(description);
result.appendChild(checkboxDiv);
}
var count = 0;
......@@ -529,7 +551,10 @@ AbstractInfoWindow.prototype._createTableForTargetDiv = function (data, overlay)
},
columns: [{
title: 'Name'
}]
}],
language: {
emptyTable: "Currently not showing any " + overlay.getName() + " entries"
}
});
$(table).on("click", "a", function () {
......
......@@ -51,7 +51,7 @@ function AliasInfoWindow(params) {
};
var dbOverlaySearchChanged = function (arg) {
return self.update().then(function(){
return self.update().then(function () {
if (arg.object instanceof ChemicalDbOverlay) {
$("a:contains(chemical)", self.getContent()).click();
} else if (arg.object instanceof DrugDbOverlay) {
......@@ -297,6 +297,7 @@ AliasInfoWindow.prototype.createChartDiv = function (params) {
result.appendChild(rows[i][j]);
}
}
result.appendChild( document.createElement("br"));
return result;
});
};
......@@ -438,7 +439,9 @@ AliasInfoWindow.prototype.createGenomicDiv = function (params) {
return Promise.all(promises).then(function (result) {
promises = [];
result.forEach(function (overlayEntries) {
overlaysData = overlaysData.concat(overlayEntries);
if (overlayEntries !== undefined) {
overlaysData = overlaysData.concat(overlayEntries);
}
});
return Promise.all(promises);
}).then(function () {
......@@ -553,6 +556,7 @@ AliasInfoWindow.prototype.createGenomicDiv = function (params) {
zoomOut.appendTo(zoomControls);
}
result.appendChild( document.createElement("br"));
return result;
} else {
return document.createElement("div");
......
package lcsb.mapviewer.commands;
import java.util.*;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import lcsb.mapviewer.common.exception.*;
import lcsb.mapviewer.common.exception.InvalidArgumentException;
import lcsb.mapviewer.common.exception.InvalidClassException;
import lcsb.mapviewer.common.exception.InvalidStateException;
import lcsb.mapviewer.model.Project;
import lcsb.mapviewer.model.graphics.PolylineData;
import lcsb.mapviewer.model.map.MiriamData;
import lcsb.mapviewer.model.map.compartment.Compartment;
import lcsb.mapviewer.model.map.kinetics.*;
import lcsb.mapviewer.model.map.kinetics.SbmlArgument;
import lcsb.mapviewer.model.map.kinetics.SbmlFunction;
import lcsb.mapviewer.model.map.kinetics.SbmlKinetics;
import lcsb.mapviewer.model.map.kinetics.SbmlParameter;
import lcsb.mapviewer.model.map.kinetics.SbmlUnit;
import lcsb.mapviewer.model.map.layout.graphics.Layer;
import lcsb.mapviewer.model.map.model.*;
import lcsb.mapviewer.model.map.reaction.*;
import lcsb.mapviewer.model.map.species.*;
import lcsb.mapviewer.model.map.model.Author;
import lcsb.mapviewer.model.map.model.ElementSubmodelConnection;
import lcsb.mapviewer.model.map.model.Model;
import lcsb.mapviewer.model.map.model.ModelData;
import lcsb.mapviewer.model.map.model.ModelFullIndexed;
import lcsb.mapviewer.model.map.model.ModelSubmodelConnection;
import lcsb.mapviewer.model.map.reaction.AbstractNode;
import lcsb.mapviewer.model.map.reaction.NodeOperator;
import lcsb.mapviewer.model.map.reaction.Reaction;
import lcsb.mapviewer.model.map.reaction.ReactionNode;
import lcsb.mapviewer.model.map.species.Complex;
import lcsb.mapviewer.model.map.species.Element;
import lcsb.mapviewer.model.map.species.Species;
/**
* Command that creates a new instance of the model with the same data.
......@@ -42,7 +65,7 @@ public class CopyCommand extends NewModelCommand {
* @return copy of the model
*/
public Model execute() {
Map<Model, Model> copies = new HashMap<>();
Map<ModelData, ModelData> copies = new HashMap<>();
Model model = getModel();
......@@ -59,16 +82,30 @@ public class CopyCommand extends NewModelCommand {
throw new InvalidStateException("Problem with copying submodel of a model");
}
Model result = createNotNestedCopy(model);
Queue<ModelData> children = new LinkedList<>();
children.add(model.getModelData());
copies.put(model, result);
while (!children.isEmpty()) {
ModelData child = children.poll();
if (copies.get(child) == null) {
for (ModelSubmodelConnection submodelConnection : model.getSubmodelConnections()) {
Model submodel = submodelConnection.getSubmodel().getModel();
Model submodelCopy = createNotNestedCopy(submodel);
copies.put(submodel, submodelCopy);
Model copy = createNotNestedCopy(child);
copies.put(child, copy.getModelData());