Commit 3b00a3b7 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge branch '1493-pin-dispaly' into merge-16.0.0-beta.2

parents c3c340b4 ae7ad1b7
Pipeline #46864 failed with stage
in 25 minutes and 56 seconds
......@@ -6,6 +6,26 @@ minerva (16.1.0~alpha.0) stable; urgency=medium
* 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;
}
}
......@@ -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());
......
......@@ -30,7 +30,7 @@
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
......
......@@ -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());
for (ModelSubmodelConnection submodelConnection : child.getSubmodels()) {
children.add(submodelConnection.getSubmodel());
}
for (Element element : child.getElements()) {
if (element.getSubmodel() != null) {
children.add(element.getSubmodel().getSubmodel());
}
}
}
}
for (Model modelCopy : copies.values()) {
Model result = copies.get(model.getModelData()).getModel();
for (ModelData modelCopy : copies.values()) {
try {
result.getProject().addModel(modelCopy);
assignModelCopies(modelCopy, copies);
......@@ -90,11 +127,11 @@ public class CopyCommand extends NewModelCommand {
* @throws InvalidModelException
* when there is inconsistency in data
*/
private void assignModelCopies(Model modelCopy, Map<Model, Model> copies) throws InvalidModelException {
for (ModelSubmodelConnection connection : modelCopy.getSubmodelConnections()) {
private void assignModelCopies(ModelData modelCopy, Map<ModelData, ModelData> copies) throws InvalidModelException {
for (ModelSubmodelConnection connection : modelCopy.getSubmodels()) {
// copy connection reference
Model original = connection.getSubmodel().getModel();
Model copy = copies.get(original);
ModelData original = connection.getSubmodel();
ModelData copy = copies.get(original);
if (copy == null) {
throw new InvalidModelException("Original model contain reference to model that wasn't copied");
}
......@@ -102,16 +139,14 @@ public class CopyCommand extends NewModelCommand {
// copy connection parent reference
if (connection.getParentModel() != null) {
original = connection.getParentModel().getModel();
if (original != null) {
copy = copies.get(original);
if (copy == null) {
if (!copies.values().contains(original)) {
throw new InvalidModelException("Original model contain reference to model that wasn't copied");
}
} else {
connection.setParentModel(copy);
original = connection.getParentModel();
copy = copies.get(original);
if (copy == null) {
if (!original.equals(modelCopy)) {
throw new InvalidModelException("Original model contain reference to model that wasn't copied");
}
} else {
connection.setParentModel(copy);
}
}
}
......@@ -120,20 +155,21 @@ public class CopyCommand extends NewModelCommand {
if (alias.getSubmodel() != null) {
ElementSubmodelConnection connection = alias.getSubmodel();
// copy information about submodel
Model original = connection.getSubmodel().getModel();
Model copy = copies.get(original);
ModelData original = connection.getSubmodel();
ModelData copy = copies.get(original);
if (copy == null) {
throw new InvalidModelException("Original model contain reference to model that wasn't copied");
}
connection.setSubmodel(copy);
// copy information about original alias
// copy information about original element
if (connection.getFromElement() != null) {
connection.setFromElement(modelCopy.getElementByElementId(connection.getFromElement().getElementId()));
connection.setFromElement(modelCopy.getModel().getElementByElementId(connection.getFromElement().getElementId()));
}
// copy information about reference alias
// copy information about reference element
if (connection.getToElement() != null) {
connection.setToElement(modelCopy.getElementByElementId(connection.getToElement().getElementId()));
connection.setToElement(modelCopy.getModel().getElementByElementId(connection.getToElement().getElementId()));
}
}
}
......@@ -147,7 +183,7 @@ public class CopyCommand extends NewModelCommand {
* original model to copy
* @return copy of the model
*/
protected Model createNotNestedCopy(Model model) {
protected Model createNotNestedCopy(ModelData model) {
Model result = new ModelFullIndexed(null);
for (SbmlUnit unit : model.getUnits()) {
......@@ -216,7 +252,7 @@ public class CopyCommand extends NewModelCommand {
for (Reaction reaction : result.getReactions()) {
updateReactionReferences(reaction, result);
}
for (ModelSubmodelConnection connection : model.getSubmodelConnections()) {
for (ModelSubmodelConnection connection : model.getSubmodels()) {
result.addSubmodelConnection(connection.copy());
}
......@@ -247,7 +283,7 @@ public class CopyCommand extends NewModelCommand {
* @param original
* original model
*/
private void assignSimpleDataToCopy(Model copy, Model original) {
private void assignSimpleDataToCopy(Model copy, ModelData original) {
copy.setName(original.getName());
copy.setWidth(original.getWidth());
......@@ -373,10 +409,10 @@ public class CopyCommand extends NewModelCommand {
* @param originalModel
* original model from which alias copy was created
*/
private void updateElementReferences(Element element, Model model, Model originalModel) {
private void updateElementReferences(Element element, Model model, ModelData originalModel) {
if (element instanceof Compartment) {
Compartment compartment = (Compartment) element;
Compartment original = originalModel.getElementByElementId(element.getElementId());
Compartment original = originalModel.getModel().getElementByElementId(element.getElementId());
for (Element child : original.getElements()) {
compartment.addElement(model.getElementByElementId(child.getElementId()));
}
......
package lcsb.mapviewer.commands;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.awt.geom.Point2D;