Commit 3513c410 authored by igoshin's avatar igoshin Committed by Matija Obreza
Browse files

Filtering data

#11886
parent e5e6cab0
......@@ -16,30 +16,21 @@
package org.genesys2.server.servlet.controller;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.genesys.ParameterCategory;
import org.genesys2.server.model.impl.Crop;
import org.genesys2.server.service.CropService;
import org.genesys2.server.service.GenesysFilterService;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.MappingService;
import org.genesys2.server.service.TaxonomyService;
import org.genesys2.server.service.TraitService;
import org.genesys2.server.service.*;
import org.genesys2.server.service.impl.GenesysFilterServiceImpl.LabelValue;
import org.genesys2.spring.ResourceNotFoundException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
......@@ -47,17 +38,12 @@ import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
@Controller
public class ExplorerController extends BaseController {
......@@ -284,7 +270,8 @@ public class ExplorerController extends BaseController {
* @param page
* @return
*/
@RequestMapping("/explore")
@SuppressWarnings("unchecked")
@RequestMapping("/explore")
public String viewFiltered(ModelMap model, @RequestParam(value = "page", required = false, defaultValue = "1") int page,
@RequestParam(value = "filter", required = true, defaultValue = "{}") String jsonFilter,
@RequestParam(value = "pick", required = false) String jsonPick) {
......@@ -292,7 +279,18 @@ public class ExplorerController extends BaseController {
if (StringUtils.isNotBlank(jsonPick)) {
// Cleanup JSON pick
try {
Map<String,List<String>> filters = mapper.readValue(jsonFilter, Map.class);
Map<String,String> pick= new HashMap<>();
for (String key:filters.keySet()){
pick.put(key,key);
}
JsonNode jsonTree = mapper.readTree(jsonPick);
model.addAttribute("test",new JSONObject(filters));
model.addAttribute("filters",filters);
model.addAttribute("pick",pick);
model.addAttribute("jsonPick", jsonTree.toString());
_logger.info("Clean jsonPick: " + jsonTree);
} catch (IOException e) {
......@@ -326,8 +324,8 @@ public class ExplorerController extends BaseController {
_logger.info("Got: " + accessions);
model.addAttribute("pagedData", accessions);
return "/accession/explore";
model.addAttribute("availableFilters", filterService.listAvailableFilters());
return "/accession/explore_new";
}
@RequestMapping(value = "/explore/ac/{field}", produces = MediaType.APPLICATION_JSON_VALUE)
......
......@@ -335,6 +335,8 @@ filter.inSvalbard=Safety duplicated in Svalbard
filter.mlsStat=MLS status of the accession
filter.available=Available for distribution
filter.download-dwca=Download DwCA
filter.add=Add filter
filter.apply=Apply
search.page.title=Full-text Search
search.no-results=No matches found for your query.
......
<!DOCTYPE html>
<%@include file="/WEB-INF/jsp/init.jsp"%>
<html>
<head>
<title><spring:message code="accession.page.data.title" /></title>
</head>
<body>
<h1>
<spring:message code="accession.page.data.title" />
</h1>
<%--Dropdown filters--%>
<div class="main-col-header clearfix">
<ul class="nav nav-pills">
<li class="dropdown form-horizontal" id="menu1">
<a class="btn btn-default dropdown-toggle" data-toggle="dropdown" href="#">
<spring:message code="filter.add"/>
<b class="glyphicon-plus"></b>
</a>
<ul class="dropdown-menu">
<c:forEach items="${availableFilters}" var="filter">
<li><a href="#" id="${filter.key}_id" onclick="enableFilter('${filter.key}')">
<spring:message code="filter.${filter.key}"/></a></li>
</c:forEach>
</ul>
</li>
</ul>
<div class="nav-header">
<c:if test="${pagedData.totalElements le 100000}">
<form class="pull-right form-horizontal" method="post" action="/explore/dwca">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<input type="hidden" name="crop" value="${crop.shortName}" />
<input type="hidden" name="filter" value="<c:out value="${jsonFilter}" />" />
<div class="row" style="margin-top: 2em;">
<div class="col-sm-4">
<button class="btn btn-default" type="submit"><spring:message code="filter.download-dwca" /></button>
</div>
</div>
</form>
</c:if>
<div class="results"><spring:message code="accessions.number" arguments="${pagedData.totalElements}" />
<a href="<c:url value="/explore/map"><c:param name="crop" value="${crop.shortName}" /><c:param name="filter">${jsonFilter}</c:param></c:url>">Map</a>
</div>
<div class="pagination">
<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: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>
</div>
</div>
</div>
<%--Filters--%>
<div id="allfilters">
<c:forEach items="${availableFilters}" var="filter">
<div class="clearfix filter-block" style="display:${pick[filter.key] eq filter.key ? '' : 'none'}"
id="${filter.key}_filter" key="${filter.key}">
<div class="col-lg-3">
<spring:message code="filter.${filter.name}"/>
</div>
<div class="col-lg-5 filter-new">
<c:choose>
<c:when test="${filter.filterType=='LIST'}">
<div class="">
<c:forEach items="${filter.options}" var="option">
<div>
<label><input class="list" type="checkbox" value="${option.value}"/> <c:out value="${option.name}"/></label>
<span class="pull-right"><c:out value="${option.count}"/></span>
</div>
</c:forEach>
</div>
</c:when>
<c:when test="${filter.filterType=='I18NLIST'}">
<div class="">
<c:forEach items="${filter.options}" var="option">
<div>
<label>
<input id="${option.value}_input" ${fn:contains(filters[filter.key], option.value)?'checked':''} i-key="${filter.key}${option.value}" type="checkbox" value="${option.value}" onclick="filterList('${filter.key}','${option.value}')"/>
<spring:message code="${option.name}"/>
</label>
</div>
</c:forEach>
</div>
</c:when>
<c:when test="${filter.filterType=='AUTOCOMPLETE'}">
<div class="ui-front">
<div class="form-group input-group">
<span class="input-group-btn">
<input id="${filter.key}_input" class="span2 form-control autocomplete-filter" x-source="${filter.autocompleteUrl}" type="text"/>
<button class="btn notimportant" onclick="filterAuto('${filter.key}')">+</button>
</span>
</div>
</div>
</c:when>
<c:when test="${filter.dataType=='NUMERIC'}">
<div class="form-group input-group">
<span class="input-group-btn">
<input id="${filter.key}_input_1" class="span5 form-control" type="text"/>
<input id="${filter.key}_input_2" class="span5 form-control" type="text"/>
<button class="btn notimportant" onclick="filterRange('${filter.key}')">+</button>
</span>
</div>
</c:when>
<c:when test="${filter.dataType=='BOOLEAN'}">
<div class="">
<div><label><input type="checkbox" ${fn:contains(filters[filter.key], 'true')?'checked':''} class="bool-data" i-key="${filter.key}true" id="${filter.key}" value="true"><spring:message code="boolean.true"/></label></div>
<div><label><input type="checkbox" ${fn:contains(filters[filter.key], 'false')?'checked':''} class="bool-data" i-key="${filter.key}false" id="${filter.key}" value="false"><spring:message code="boolean.false"/></label></div>
<div><label><input type="checkbox" ${fn:contains(filters[filter.key], 'null')?'checked':''} class="bool-data" i-key="${filter.key}null" id="${filter.key}" value="null"><spring:message code="boolean.null"/></label></div>
</div>
</c:when>
<c:otherwise>
<div class="form-group input-group">
<span class="input-group-btn">
<input class="span2 form-control" id="${filter.key}_input" type="text"/>
<button class="btn notimportant" onclick="filterAuto('${filter.key}')">+</button>
</span>
</div>
</c:otherwise>
</c:choose>
</div>
<div class="col-lg-4 filter-values" id="${filter.key}_value">
<a href="#" style="float: right" class="close">x</a>
<c:forEach items="${filters[filter.key]}" var="value">
<c:set var="string" value="${value}"/>
<c:if test="${fn:contains(value, 'range')}">
<c:set var="string" value="${fn:replace(value,'{range=[','Between ')}"/>
<c:set var="string" value="${fn:replace(string,',',' and ')}"/>
<c:set var="string" value="${fn:replace(string,']}','')}"/>
</c:if>
<c:if test="${fn:contains(value, 'min')}">
<c:set var="string" value="${fn:replace(value,'{min=','More than ')}"/>
<c:set var="string" value="${fn:replace(string,'}','')}"/>
</c:if>
<c:if test="${fn:contains(value, 'max')}">
<c:set var="string" value="${fn:replace(value,'{max=','Less than ')}"/>
<c:set var="string" value="${fn:replace(string,'}','')}"/>
</c:if>
<div class="filtval complex" x-key="${filter.key}${value}" id="${filter.key}">${string}</div>
</c:forEach>
</div>
</div>
</c:forEach>
<div class="row">
<div style="text-align: center">
<button id="apply" class="btn btn-green"><spring:message code="filter.apply"/></button>
</div>
</div>
</div>
<%--Accessions--%>
<table class="accessions">
<thead>
<tr>
<td class="idx-col"></td>
<td />
<td><spring:message code="accession.accessionName" /></td>
<td><spring:message code="accession.taxonomy" /></td>
<td class="notimportant"><spring:message code="accession.origin" /></td>
<td class="notimportant"><spring:message code="accession.sampleStatus" /></td>
<td class="notimportant"><spring:message code="accession.holdingInstitute" /></td>
<%-- <td><spring:message code="accession.holdingCountry" /></td>
--%>
</tr>
</thead>
<tbody>
<c:forEach items="${pagedData.content}" var="accession" varStatus="status">
<tr class="acn ${status.count % 2 == 0 ? 'even' : 'odd'}">
<td class="idx-col">${status.count + pagedData.size * pagedData.number}</td>
<td class="sel" x-aid="${accession.id}"></td>
<td><a href="<c:url value="/acn/id/${accession.id}" />"><b><c:out value="${accession.accessionName}" /></b></a></td>
<%-- <td><a href="<c:url value="/acn/t/${accession.taxonomy.genus}/${accession.taxonomy.species}" />"><c:out value="${accession.taxonomy.taxonName}" /></a></td> --%>
<td><c:out value="${accession.taxonomy.taxonName}" /></td>
<%-- <td class="notimportant"><a href="<c:url value="/geo/${accession.origin.toLowerCase()}" />"><c:out value="${accession.countryOfOrigin.name}" /></a></td> --%>
<td class="notimportant"><c:out value="${accession.countryOfOrigin.getName(pageContext.response.locale)}" /></td>
<td class="notimportant"><spring:message code="accession.sampleStatus.${accession.sampleStatus}" /></td>
<td class="notimportant"><a href="<c:url value="/wiews/${accession.institute.code.toLowerCase()}" />"><c:out value="${accession.institute.code}" /></a></td>
<%-- <td><a href="<c:url value="/geo/${accession.institute.country.code3.toLowerCase()}" />"><c:out value="${accession.institute.country.name}" /></a></td>
--%>
</tr>
</c:forEach>
</tbody>
</table>
<content tag="javascript">
<script type="text/javascript">
var jsonData = ${jsonFilter};
var filterPick = [];
function setCharAt(str,index,chr) {
if(index > str.length-1) return str;
return str.substr(0,index) + chr + str.substr(index+1);
}
function submitJson() {
for (var key in jsonData) {
filterPick.push(key);
}
var filter = JSON.stringify(jsonData);
var pick = JSON.stringify(filterPick);
var url='/explore?filter=' + filter + "&pick=" + pick;
window.location.href = encodeURI(url);
}
function existInJson(input, key) {
var exist = input != '';
var array = jsonData[key];
for (var val in array) {
if (array[val] == input) {
exist = false;
}
}
return exist;
}
function enableFilter(key) {
var editId = "#" + key + "_filter";
$(editId).show();
}
function appendHtml(key, value) {
var valueId = "#" + key + "_value";
var div = "<div class='filtval complex' x-key='" + key + value + "' id='" + key + "'>" + value + "</div>"
$(valueId).append(div);
}
function collectData(key,value) {
var jsonValue = [];
var exist = jsonData[key] != null;
if(exist){
jsonValue=jsonData[key];
}
jsonValue.push(value);
return jsonValue;
}
function removeValue(value, key) {
var array = jsonData[key];
for (var val in array) {
var isJson = value.indexOf("{") > -1;
var jsonArray = array[val];
if (isJson) {
jsonArray = JSON.stringify(jsonArray);
}
if (jsonArray == value) {
array.splice(val, 1);
}
if (array.length == 0) {
delete jsonData[key];
}
}
}
function filterAuto(key) {
var inputId = "#" + key + "_input";
var value = $(inputId).val();
if (existInJson(value, key)) {
appendHtml(key, value);
jsonData[key] = collectData(key,value);
$(inputId).val('');
}
}
function filterRange(key) {
var inputId1 = "#" + key + "_input_1";
var inputId2 = "#" + key + "_input_2";
var inputValue1 = $(inputId1).val();
var inputValue2 = $(inputId2).val();
var value = null;
var range = {};
var rangeValue = [];
var jsonValue = [];
var exist = jsonData[key] != null;
if (exist) {
jsonValue = jsonData[key];
}
if (!isNaN(inputValue1) && !isNaN(inputValue2)) {
if (inputValue1 == inputValue2) {
jsonValue.push(parseFloat(inputValue1));
value = inputValue1;
} else if (inputValue1 != '' && inputValue2 == '') {
range["min"] = parseFloat(inputValue1);
jsonValue.push(range);
value = "More than " + inputValue1;
} else if (inputValue1 == '' && inputValue2 != '') {
range["max"] = parseFloat(inputValue2);
jsonValue.push(range);
value = "Less than " + inputValue2;
} else if (inputValue1 != '' && inputValue2 != '') {
rangeValue.push(parseFloat(inputValue1));
rangeValue.push(parseFloat(inputValue2));
range["range"] = rangeValue;
jsonValue.push(range);
value = "Between " + inputValue1 + " and " + inputValue2;
}
appendHtml(key, value);
jsonData[key] = jsonValue;
$(inputId1).val('');
$(inputId2).val('');
}
}
function filterList(key, option) {
var inputId = "#" + option + "_input";
var value = $(inputId).val();
var checked = $(inputId).is(":checked");
if (checked && existInJson(value, key)) {
appendHtml(key, value);
jsonData[key] = collectData(key,value);
} else {
var xkey = key + value;
removeValue(value, key);
$('div[x-key=' + xkey + ']').remove();
}
}
$(".bool-data").on("click", function () {
var value = $(this).val();
var key = $(this).attr("id");
var checked = $(this).is(":checked");
if (checked && existInJson(value, key)) {
appendHtml(key, value);
jsonData[key] = collectData(key,value);
} else {
var xkey = key + value;
removeValue(value, key);
$('div[x-key=' + xkey + ']').remove();
}
});
$("#apply").click(function () {
submitJson()
});
$(".close").on("click", function () {
var parent = $(this).parent().parent();
var key = parent.attr("key");
console.log(key);
delete jsonData[key];
parent.hide();
});
$("body").on("click", ".filtval", function (event) {
event.preventDefault();
var key = $(this).attr("id");
var value = $(this).attr("x-key").replace(key,"");
if(value.indexOf("{") > -1){
var jsonVal=value.replace("=",":").replace(" ","");
value = setCharAt(jsonVal, jsonVal.indexOf("{"), '{"');
value = setCharAt(value, jsonVal.indexOf(":") + 1, '":');
}
removeValue(value, key);
$(this).remove();
$('input[i-key=' + key + value + ']').prop('checked', false);
});
$(".autocomplete-filter").each(function () {
var t = $(this);
t.autocomplete({ delay: 200, minLength: 3, source: t.attr('x-source'), messages: { noResults: '', results: function () {
} } });
});
</script>
</content>
</body>
</html>
\ No newline at end of file
......@@ -2,4 +2,5 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
\ No newline at end of file
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
\ No newline at end of file
......@@ -1891,4 +1891,8 @@ html[dir="rtl"] ul.statistics .stats-number {
.ui-autocomplete.ui-widget {
z-index: 100;
}
.close.filter {
font-size: 15px;
}
\ No newline at end of file
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