Commit 125c6455 authored by Matija Obreza's avatar Matija Obreza
Browse files

Explore: Version 1

parent 576bce8b
...@@ -19,10 +19,10 @@ package org.genesys2.server.servlet.controller; ...@@ -19,10 +19,10 @@ package org.genesys2.server.servlet.controller;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map.Entry;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.genesys2.server.model.genesys.Accession; import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.genesys.ParameterCategory; import org.genesys2.server.model.genesys.ParameterCategory;
...@@ -39,6 +39,7 @@ import org.springframework.data.domain.Page; ...@@ -39,6 +39,7 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.social.ResourceNotFoundException;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
...@@ -50,6 +51,8 @@ import org.springframework.web.bind.annotation.ResponseBody; ...@@ -50,6 +51,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
@Controller @Controller
public class ExplorerController extends BaseController { public class ExplorerController extends BaseController {
...@@ -74,6 +77,34 @@ public class ExplorerController extends BaseController { ...@@ -74,6 +77,34 @@ public class ExplorerController extends BaseController {
private ObjectMapper mapper = new ObjectMapper(); private ObjectMapper mapper = new ObjectMapper();
/**
* Action method to navigate to filter selection
*/
@RequestMapping(value = "/explore", method = RequestMethod.POST, params = { "doPick" })
public String exploreActionPick(ModelMap model, @RequestParam(value = "filter", required = false, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = false) String jsonPick, @RequestParam(value = "crop", required = false) String shortName) {
model.addAttribute("filter", jsonFilter);
model.addAttribute("pick", jsonPick);
if (StringUtils.isNotBlank(shortName))
model.addAttribute("crop", shortName);
return "redirect:/explore/pick";
}
/**
* Action method to view filtered data
*/
@RequestMapping(value = "/explore", method = RequestMethod.POST, params = { "doView" })
public String exploreActionView(ModelMap model, @RequestParam(value = "filter", required = false, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = false) String jsonPick, @RequestParam(value = "crop", required = false) String shortName) {
model.addAttribute("filter", jsonFilter);
model.addAttribute("pick", jsonPick);
if (StringUtils.isNotBlank(shortName))
model.addAttribute("crop", shortName);
return "redirect:/explore";
}
@RequestMapping(value = "/explore/pick", method = RequestMethod.GET) @RequestMapping(value = "/explore/pick", method = RequestMethod.GET)
public String pickFilters(ModelMap model, @RequestParam(value = "filter", required = false, defaultValue = "{}") String jsonFilter, public String pickFilters(ModelMap model, @RequestParam(value = "filter", required = false, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = false, defaultValue = "[]") String pick, @RequestParam(value = "crop", required = false) String shortName) { @RequestParam(value = "pick", required = false, defaultValue = "[]") String pick, @RequestParam(value = "crop", required = false) String shortName) {
...@@ -99,7 +130,7 @@ public class ExplorerController extends BaseController { ...@@ -99,7 +130,7 @@ public class ExplorerController extends BaseController {
// What filters do we support? // What filters do we support?
model.addAttribute("availableFilters", filterService.listAvailableFilters()); model.addAttribute("availableFilters", filterService.listAvailableFilters());
model.addAttribute("jsonString", jsonFilter); model.addAttribute("jsonFilter", jsonFilter);
model.addAttribute("selectedFilters", new HashSet<String>(Arrays.asList(selectedFilters))); model.addAttribute("selectedFilters", new HashSet<String>(Arrays.asList(selectedFilters)));
model.addAttribute("crops", cropService.list(getLocale())); model.addAttribute("crops", cropService.list(getLocale()));
return "/filter/pick"; return "/filter/pick";
...@@ -122,7 +153,20 @@ public class ExplorerController extends BaseController { ...@@ -122,7 +153,20 @@ public class ExplorerController extends BaseController {
_logger.error(e.getMessage(), e); _logger.error(e.getMessage(), e);
} }
model.addAttribute("filter", jsonFilter); // Keep only picked descriptors
try {
_logger.info("Cleaning up unused filters : " + jsonFilter);
ObjectNode jsonTree = (ObjectNode) mapper.readTree(jsonFilter);
for (String filter : IteratorUtils.toList(jsonTree.fieldNames())) {
if (!ArrayUtils.contains(pick, filter)) {
jsonTree.remove(filter);
}
}
model.addAttribute("filter", jsonTree.toString());
} catch (IOException e) {
_logger.error("Invalid JSON for pick", e);
}
return "redirect:/explore/pick"; return "redirect:/explore/pick";
} }
...@@ -136,7 +180,6 @@ public class ExplorerController extends BaseController { ...@@ -136,7 +180,6 @@ public class ExplorerController extends BaseController {
return "redirect:/explore/filter"; return "redirect:/explore/filter";
} }
@RequestMapping(value = "/explore/filter", method = RequestMethod.GET) @RequestMapping(value = "/explore/filter", method = RequestMethod.GET)
public String showFilters(ModelMap model, @RequestParam(value = "filter", required = false, defaultValue = "{}") String jsonFilter, public String showFilters(ModelMap model, @RequestParam(value = "filter", required = false, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = false) String pick, @RequestParam(value = "crop", required = false) String shortName) { @RequestParam(value = "pick", required = false) String pick, @RequestParam(value = "crop", required = false) String shortName) {
...@@ -154,13 +197,14 @@ public class ExplorerController extends BaseController { ...@@ -154,13 +197,14 @@ public class ExplorerController extends BaseController {
try { try {
JsonNode jsonTree = mapper.readTree(jsonFilter); JsonNode jsonTree = mapper.readTree(jsonFilter);
model.addAttribute("jsonString", jsonTree.toString()); model.addAttribute("jsonFilter", jsonTree.toString());
} catch (NullPointerException | IOException e) { } catch (NullPointerException | IOException e) {
_logger.warn(e.getMessage(), e); _logger.warn(e.getMessage(), e);
} }
try { try {
model.addAttribute("pick", mapper.writeValueAsString(selectedFilters)); if (selectedFilters != null && selectedFilters.length > 0)
model.addAttribute("pick", mapper.writeValueAsString(selectedFilters));
} catch (IOException e) { } catch (IOException e) {
_logger.warn(e.getMessage(), e); _logger.warn(e.getMessage(), e);
} }
...@@ -175,6 +219,44 @@ public class ExplorerController extends BaseController { ...@@ -175,6 +219,44 @@ public class ExplorerController extends BaseController {
return "/filter/filter"; return "/filter/filter";
} }
/**
* Redirect to /explore/c/{shortName} if parameter 'crop' is provided
*/
@RequestMapping(value = "/explore", params = { "crop" })
private String x(ModelMap model, @RequestParam(value = "filter", required = true, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = true, defaultValue = "") String jsonPick, @RequestParam(value = "crop") String shortName) {
model.addAttribute("filter", jsonFilter);
model.addAttribute("pick", jsonPick);
if (StringUtils.isNotBlank(shortName)) {
Crop crop = cropService.getCrop(shortName);
if (crop == null) {
throw new ResourceNotFoundException("No crop " + shortName);
}
return "redirect:/explore/c/" + crop.getShortName();
}
return "redirect:/explore";
}
/**
* Explore accessions filtered within a crop
*/
@RequestMapping("/explore/c/{crop}")
public String viewFiltered(ModelMap model, @PathVariable("crop") String shortName,
@RequestParam(value = "page", required = false, defaultValue = "1") int page,
@RequestParam(value = "filter", required = true, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = true, defaultValue = "") String jsonPick) {
Crop crop = cropService.getCrop(shortName);
if (crop == null) {
throw new ResourceNotFoundException("No crop " + shortName);
}
model.addAttribute("crop", crop);
return viewFiltered(model, page, jsonFilter, jsonPick);
}
/** /**
* Browse all * Browse all
...@@ -185,25 +267,40 @@ public class ExplorerController extends BaseController { ...@@ -185,25 +267,40 @@ public class ExplorerController extends BaseController {
*/ */
@RequestMapping("/explore") @RequestMapping("/explore")
public String viewFiltered(ModelMap model, @RequestParam(value = "page", required = false, defaultValue = "1") int page, public String viewFiltered(ModelMap model, @RequestParam(value = "page", required = false, defaultValue = "1") int page,
@RequestParam(value = "filter", required = true, defaultValue = "{}") String jsonFilter) { @RequestParam(value = "filter", required = true, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = false) String jsonPick) {
if (StringUtils.isNotBlank(jsonPick)) {
// Cleanup JSON pick
try {
JsonNode jsonTree = mapper.readTree(jsonPick);
model.addAttribute("jsonPick", jsonTree.toString());
_logger.info("Clean jsonPick: " + jsonTree);
} catch (IOException e) {
_logger.error("Invalid JSON for pick", e);
}
}
_logger.info("Filtering by: " + jsonFilter); _logger.info("Filtering by: " + jsonFilter);
ObjectMapper mapper = new ObjectMapper(); ObjectNode jsonTree = null;
JsonNode jsonTree = null;
try { try {
jsonTree = mapper.readTree(jsonFilter); jsonTree = (ObjectNode) mapper.readTree(jsonFilter);
_logger.debug(jsonTree.toString()); _logger.debug(jsonTree.toString());
model.addAttribute("jsonString", jsonTree.toString()); if (model.containsAttribute("crop")) {
model.addAttribute("jsonFilter", jsonTree); jsonTree.remove("crop");
model.addAttribute("jsonFilter", jsonTree.toString());
Iterator<Entry<String, JsonNode>> fields = jsonTree.fields(); // Replace any other crop filters...
while (fields.hasNext()) { ArrayNode oneCrop = jsonTree.arrayNode();
Entry<String, JsonNode> entry = fields.next(); oneCrop.add(((Crop) model.get("crop")).getShortName());
_logger.debug("2=" + entry.getKey() + " = " + entry.getValue()); jsonTree.put("crop", oneCrop);
} else {
model.addAttribute("jsonFilter", jsonTree.toString());
} }
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); _logger.error(e.getMessage(), e);
} }
Page<Accession> accessions = filterService.listAccessions(jsonTree, new PageRequest(page - 1, 50, new Sort("acceNumb"))); Page<Accession> accessions = filterService.listAccessions(jsonTree, new PageRequest(page - 1, 50, new Sort("acceNumb")));
...@@ -214,7 +311,6 @@ public class ExplorerController extends BaseController { ...@@ -214,7 +311,6 @@ public class ExplorerController extends BaseController {
return "/accession/explore"; return "/accession/explore";
} }
@RequestMapping(value = "/explore/ac/{field}", produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(value = "/explore/ac/{field}", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody @ResponseBody
public List<LabelValue<String>> autocomplete(@PathVariable("field") String filter, @RequestParam(value = "term", required = false) String ac) { public List<LabelValue<String>> autocomplete(@PathVariable("field") String filter, @RequestParam(value = "term", required = false) String ac) {
......
...@@ -16,18 +16,16 @@ ...@@ -16,18 +16,16 @@
<div class="results"><spring:message code="accessions.number" arguments="${pagedData.totalElements}" /></div> <div class="results"><spring:message code="accessions.number" arguments="${pagedData.totalElements}" /></div>
<div class="pagination"> <div class="pagination">
<spring:message code="paged.pageOfPages" arguments="${pagedData.number+1},${pagedData.totalPages}" /> <spring:message code="paged.pageOfPages" arguments="${pagedData.number+1},${pagedData.totalPages}" />
<a href="<spring:url value=""><spring:param name="page" value="${pagedData.number eq 0 ? 1 : pagedData.number}" /><spring:param name="filter" value="${jsonFilter}" /></spring:url>"><spring:message code="pagination.previous-page" /></a> <a href="<spring:url value=""><spring:param name="page" value="${pagedData.number eq 0 ? 1 : pagedData.number}" /><spring:param name="filter" value="${jsonFilter}" /><spring:param name="pick" value="${jsonPick}" /></spring:url>"><spring:message code="pagination.previous-page" /></a>
<a href="<spring:url value=""><spring:param name="page" value="${pagedData.number+2}" /><spring:param name="filter" value="${jsonFilter}" /><spring:param name="pick" value="${jsonPick}" /></spring:url>"><spring:message code="pagination.next-page" /></a> <a href="<spring:url value=""><spring:param name="page" value="${pagedData.number+2}" /><spring:param name="filter" value="${jsonFilter}" /><spring:param name="pick" value="${jsonPick}" /></spring:url>"><spring:message code="pagination.next-page" /></a>
</div> </div>
</div> </div>
</div> </div>
<c:if test="${filters eq null and jsonFilter ne null}"> <div class="applied-filters">
<div class="applied-filters"> <spring:message code="filters.data-is-filtered" />
<spring:message code="filters.data-is-filtered" /> <a href="<spring:url value="/explore/filter"><spring:param name="crop" value="${crop.shortName}" /><spring:param name="filter" value="${jsonFilter}" /><spring:param name="pick" value="${jsonPick}" /></spring:url>"><spring:message code="filters.modify-filters" /></a>
<a href="<spring:url value="/explore/filter"><spring:param name="filter" value="${jsonFilter}" /><spring:param name="pick" value="${jsonPick}" /></spring:url>"><spring:message code="filters.modify-filters" /></a> </div>
</div>
</c:if>
<c:if test="${filters ne null}"> <c:if test="${filters ne null}">
<div class="applied-filters"> <div class="applied-filters">
......
...@@ -65,16 +65,19 @@ ...@@ -65,16 +65,19 @@
</div> </div>
</c:forEach> </c:forEach>
<div class="row"> <form method="post" action="<c:url value="/explore" />">
<div class="col-lg-offset-3 col-lg-9"> <input type="hidden" id="filtersHref" name="filter" value='${jsonFilter}' />
<a id="filtersHref" href=""><button class="btn btn-green pull-left">View!</button></a> <input type="hidden" name="pick" value='${pick}' />
<c:url var="pickUrl" value="/explore/pick"> <c:if test="${crop ne null}">
<c:param name="pick">${pick}</c:param> <input type="hidden" name="crop" value="${crop.shortName}" />
<c:param name="crop"><c:out value="${crop.shortName}" /></c:param> </c:if>
</c:url> <div class="row">
<a href="${pickUrl}"><button class="btn btn-green pull-left">Change filters</button></a> <div class="col-lg-offset-3 col-lg-9">
<button type="submit" name="doView" class="btn btn-green pull-left">View!</button>
<button type="submit" name="doPick" class="btn btn-green pull-left">Change filters</button>
</div>
</div> </div>
</div> </form>
</div> </div>
...@@ -85,11 +88,11 @@ ...@@ -85,11 +88,11 @@
<script type="text/javascript" src="<c:url value="/html/js/jquery-ui.min.js" />"></script> <script type="text/javascript" src="<c:url value="/html/js/jquery-ui.min.js" />"></script>
<script type="text/javascript"> <script type="text/javascript">
jQuery(document).ready(function() { jQuery(document).ready(function() {
// alert('${jsonString}'); // alert('${jsonFilter}');
var pick=[]; var pick=[];
var filters={}; var filters={};
try { try {
filters=$.parseJSON('${jsonString}'); filters=$.parseJSON('${jsonFilter}');
} catch (e) {console.error(e);} } catch (e) {console.error(e);}
try { try {
pick=$.parseJSON('${pick}'); pick=$.parseJSON('${pick}');
...@@ -133,7 +136,7 @@ jQuery(document).ready(function() { ...@@ -133,7 +136,7 @@ jQuery(document).ready(function() {
refreshJson: function(newFilter) { refreshJson: function(newFilter) {
$("#filtersJson").html(JSON.stringify(newFilter)); $("#filtersJson").html(JSON.stringify(newFilter));
$("#filtersHref").attr("href", "<c:url value="/explore" />?<c:if test="${crop ne null}">crop=${crop.shortName}&</c:if>filter="+JSON.stringify(newFilter)+"&pick="+JSON.stringify(pick)); $("#filtersHref").val(JSON.stringify(newFilter));
}, },
addFilterValue: function(element) { addFilterValue: function(element) {
...@@ -205,8 +208,8 @@ jQuery(document).ready(function() { ...@@ -205,8 +208,8 @@ jQuery(document).ready(function() {
} }
}; };
[<c:forEach items="${selectedFilters}" var="filter" varStatus="status">${status.index gt 0 ? ',' : ''} "${filter.name.replace(':','_')}"</c:forEach> ].forEach(function(name) { [<c:forEach items="${selectedFilters}" var="filter" varStatus="status">${status.index gt 0 ? ',' : ''} "${filter.name}"</c:forEach> ].forEach(function(name) {
FF.updateValues("#filter-" + name + ".filter-values", name, filters[name]); FF.updateValues("#filter-" + name.replace(':','_') + ".filter-values", name, filters[name]);
}); });
$("body").on("click", ".filtval", function(event) { $("body").on("click", ".filtval", function(event) {
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<h1><spring:message code="filters.view" /></h1> <h1><spring:message code="filters.view" /></h1>
<form method="post" action="<c:url value="/explore/pick" />"> <form method="post" action="<c:url value="/explore/pick" />">
<input type="hidden" name="filter" value="<c:out value="${jsonString}" />" /> <input type="hidden" name="filter" value="<c:out value="${jsonFilter}" />" />
<div id="allfilters"> <div id="allfilters">
<h2><c:out value="MCPD" /></h2> <h2><c:out value="MCPD" /></h2>
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
<ul class="nav"> <ul class="nav">
<li><a class="show" href="<c:url value="/acn/" />"><spring:message code="crop.all-crops" /></a></li> <li><a class="show" href="<c:url value="/acn/" />"><spring:message code="crop.all-crops" /></a></li>
<c:forEach items="${cropList}" var="crop" varStatus="status"> <c:forEach items="${cropList}" var="crop" varStatus="status">
<li><a class="show" href="/c/${crop.shortName}/data"><c:out value="${crop.getName(pageContext.response.locale)}" /></a></li> <li><a class="show" href="/explore/c/${crop.shortName}"><c:out value="${crop.getName(pageContext.response.locale)}" /></a></li>
</c:forEach> </c:forEach>
</ul> </ul>
</div> </div>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment