Commit d62ab996 authored by Jean-Baptiste Nizet's avatar Jean-Baptiste Nizet Committed by Exbrayat Cédric
Browse files

feat: study card

parent faea8b5c
package fr.inra.urgi.faidare.web.study;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.common.collect.Lists;
import fr.inra.urgi.faidare.api.NotFoundException;
import fr.inra.urgi.faidare.config.FaidareProperties;
import fr.inra.urgi.faidare.domain.criteria.GermplasmPOSTSearchCriteria;
import fr.inra.urgi.faidare.domain.data.TrialVO;
import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
import fr.inra.urgi.faidare.domain.data.study.StudyDetailVO;
import fr.inra.urgi.faidare.domain.data.variable.ObservationVariableVO;
import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
import fr.inra.urgi.faidare.repository.es.GermplasmRepository;
import fr.inra.urgi.faidare.repository.es.StudyRepository;
import fr.inra.urgi.faidare.repository.es.TrialRepository;
import fr.inra.urgi.faidare.repository.es.XRefDocumentRepository;
import fr.inra.urgi.faidare.repository.file.CropOntologyRepository;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* Controller used to display a study card based on its ID.
* @author JB Nizet
*/
@Controller("webStudyController")
@RequestMapping("/studies")
public class StudyController {
private final StudyRepository studyRepository;
private final FaidareProperties faidareProperties;
private final XRefDocumentRepository xRefDocumentRepository;
private final GermplasmRepository germplasmRepository;
private final CropOntologyRepository cropOntologyRepository;
private final TrialRepository trialRepository;
public StudyController(StudyRepository studyRepository,
FaidareProperties faidareProperties,
XRefDocumentRepository xRefDocumentRepository,
GermplasmRepository germplasmRepository,
CropOntologyRepository cropOntologyRepository,
TrialRepository trialRepository) {
this.studyRepository = studyRepository;
this.faidareProperties = faidareProperties;
this.xRefDocumentRepository = xRefDocumentRepository;
this.germplasmRepository = germplasmRepository;
this.cropOntologyRepository = cropOntologyRepository;
this.trialRepository = trialRepository;
}
@GetMapping("/{studyId}")
public ModelAndView site(@PathVariable("studyId") String studyId) {
StudyDetailVO study = studyRepository.getById(studyId);
// List<XRefDocumentVO> crossReferences = xRefDocumentRepository.find(
// XRefDocumentSearchCriteria.forXRefId(site.getLocationDbId()));
List<XRefDocumentVO> crossReferences = Arrays.asList(
createXref("foobar"),
createXref("bazbing")
);
// LocationVO site = createSite();
if (study == null) {
throw new NotFoundException("Study with ID " + studyId + " not found");
}
List<GermplasmVO> germplasms = getGermplasms(study);
List<ObservationVariableVO>variables = getVariables(study);
List<TrialVO> trials = getTrials(study);
return new ModelAndView("study",
"model",
new StudyModel(
study,
faidareProperties.getByUri(study.getSourceUri()),
germplasms,
variables,
trials,
crossReferences
)
);
}
private List<GermplasmVO> getGermplasms(StudyDetailVO study) {
if (study.getGermplasmDbIds() == null || study.getGermplasmDbIds().isEmpty()) {
return Collections.emptyList();
} else {
GermplasmPOSTSearchCriteria germplasmCriteria = new GermplasmPOSTSearchCriteria();
germplasmCriteria.setGermplasmDbIds(Lists.newArrayList(study.getGermplasmDbIds()));
return germplasmRepository.find(germplasmCriteria)
.stream()
.sorted(Comparator.comparing(GermplasmVO::getGermplasmName))
.collect(Collectors.toList());
}
}
private List<ObservationVariableVO> getVariables(StudyDetailVO study) {
Set<String> variableIds = studyRepository.getVariableIds(study.getStudyDbId());
return cropOntologyRepository.getVariableByIds(variableIds)
.stream()
.sorted(Comparator.comparing(ObservationVariableVO::getObservationVariableDbId))
.collect(Collectors.toList());
}
private List<TrialVO> getTrials(StudyDetailVO study) {
if (study.getTrialDbIds() == null || study.getTrialDbIds().isEmpty()) {
return Collections.emptyList();
}
return study.getTrialDbIds()
.stream()
.sorted(Comparator.naturalOrder())
.map(trialRepository::getById)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
private XRefDocumentVO createXref(String name) {
XRefDocumentVO xref = new XRefDocumentVO();
xref.setName(name);
xref.setDescription("A very large description for the xref " + name + " which has way more than 120 characters bla bla bla bla bla bla bla bla bla bla bla bla");
xref.setDatabaseName("db_" + name);
xref.setUrl("https://google.com");
xref.setEntryType("type " + name);
return xref;
}
}
package fr.inra.urgi.faidare.web.study;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import fr.inra.urgi.faidare.domain.data.LocationVO;
import fr.inra.urgi.faidare.domain.data.TrialVO;
import fr.inra.urgi.faidare.domain.data.germplasm.GermplasmVO;
import fr.inra.urgi.faidare.domain.data.study.StudyDetailVO;
import fr.inra.urgi.faidare.domain.data.variable.ObservationVariableVO;
import fr.inra.urgi.faidare.domain.datadiscovery.data.DataSource;
import fr.inra.urgi.faidare.domain.xref.XRefDocumentVO;
/**
* The model used by the study page
* @author JB Nizet
*/
public final class StudyModel {
private final StudyDetailVO study;
private final DataSource source;
private final List<GermplasmVO> germplasms;
private final List<ObservationVariableVO> variables;
private final List<TrialVO> trials;
private final List<XRefDocumentVO> crossReferences;
private final List<Map.Entry<String, Object>> additionalInfoProperties;
public StudyModel(StudyDetailVO study,
DataSource source,
List<GermplasmVO> germplasms,
List<ObservationVariableVO> variables,
List<TrialVO> trials,
List<XRefDocumentVO> crossReferences) {
this.study = study;
this.source = source;
this.germplasms = germplasms;
this.variables = variables;
this.trials = trials;
this.crossReferences = crossReferences;
Map<String, Object> additionalInfo =
study.getAdditionalInfo() == null ? Collections.emptyMap() : study.getAdditionalInfo().getProperties();
this.additionalInfoProperties =
additionalInfo.entrySet()
.stream()
.filter(entry -> entry.getValue() != null && !entry.getValue().toString().isEmpty())
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toList());
}
public StudyDetailVO getStudy() {
return study;
}
public DataSource getSource() {
return source;
}
public List<XRefDocumentVO> getCrossReferences() {
return crossReferences;
}
public List<GermplasmVO> getGermplasms() {
return germplasms;
}
public List<ObservationVariableVO> getVariables() {
return variables;
}
public List<TrialVO> getTrials() {
return trials;
}
public List<Map.Entry<String, Object>> getAdditionalInfoProperties() {
return additionalInfoProperties;
}
}
<!DOCTYPE html>
<html
xmlns:th="http://www.thymeleaf.org"
th:replace="~{layout/main :: layout(title=~{::title}, content=~{::main})}"
>
<head>
<title>Study <th:block th:text="${model.study.studyType}" />: <th:block th:text="${model.study.studyName}" /></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<main>
<h1>Study <th:block th:text="${model.study.studyType}" />: <th:block th:text="${model.study.studyName}" /></h1>
<h2>Identification</h2>
<div th:replace="fragments/row::text-row(label='Name', text=${model.study.studyName})"></div>
<div th:replace="fragments/row::text-row(label='Identifier', text=${model.study.studyDbId})"></div>
<th:block th:if="${model.source != null}">
<div th:replace="fragments/row::row(label='Source', content=~{::#source}, text='')">
<a id="source" target="_blank" th:href="${model.source.url}">
<img style="max-height: 60px;" th:src="${model.source.image}" th:alt="${model.source.name} + ' logo'" />
</a>
</div>
</th:block>
<th:block th:if="${model.study.url != null && model.source != null}">
<div th:replace="fragments/row::row(label='Data link', content=~{::#url}, text='')">
<a id="url" target="_blank" th:href="${model.study.url}">
Link to this study on <th:block th:text="${model.source.name}" />
</a>
</div>
</th:block>
<div th:replace="fragments/row::text-row(label='Project name', text=${model.study.programName})"></div>
<div th:replace="fragments/row::text-row(label='Description', text=${model.study.studyDescription})"></div>
<th:block th:if="${model.study.active != null}">
<div th:replace="fragments/row::text-row(label='Active', text=${model.study.active ? 'Yes' : 'No'})"></div>
</th:block>
<th:block th:unless="${#lists.isEmpty(model.study.seasons)}">
<div th:replace="fragments/row::text-row(label='Seasons', text=${#strings.listJoin(model.study.seasons, ',')})"></div>
</th:block>
<th:block th:if="${model.study.startDate != null && model.study.endDate != null}">
<div th:replace="fragments/row::text-row(label='Date', text=${'From ' + #dates.format(model.study.startDate, 'yyyy-MM-dd') + ' to ' + #dates.format(model.study.endDate, 'yyyy-MM-dd') })"></div>
</th:block>
<th:block th:if="${model.study.startDate != null && model.study.endDate == null}">
<div th:replace="fragments/row::text-row(label='Date', text=${'Started on ' + #dates.format(model.study.startDate, 'yyyy-MM-dd')})"></div>
</th:block>
<th:block th:if="${model.study.locationDbId}">
<div th:replace="fragments/row::row(label='Location name', content=~{::#location})">
<a id="location" th:href="@{/sites/{siteId}(siteId=${model.study.locationDbId})}" th:text="${model.study.locationName}"></a>
</div>
</th:block>
<th:block th:unless="${#lists.isEmpty(model.study.dataLinks)}">
<div th:replace="fragments/row::row(label='Data files', content=~{::#data-files})">
<ul id="data-files" class="list-unstyled">
<li th:each="dataLink : ${model.study.dataLinks}">
<a target="_blank" th:href="${dataLink.url}" th:text="${dataLink.name}"></a>
</li>
</ul>
</div>
</th:block>
<th:block th:unles="${#lists.isEmpty(model.germplasms)}">
<h2>Genotype</h2>
<div class="table-responsive scroll-table table-card-body">
<div class="card">
<table class="table table-sm table-striped">
<thead>
<tr>
<th scope="col">Accession number</th>
<th scope="col">Name</th>
<th scope="col">Taxon</th>
</tr>
</thead>
<tbody>
<tr th:each="row : ${model.germplasms}">
<td>
<a th:href="@{/germplasms/{germplasmId}(germplasmId=${row.germplasmDbId})}" th:text="${row.accessionNumber}"></a>
</td>
<td th:text="${row.germplasmName}"></td>
<td th:text="${(row.genus == null ? '' : row.genus) + ' ' + (row.species == null ? '' : row.species)+ ' ' + (row.subtaxa == null ? '' : row.subtaxa) }"></td>
</tr>
</tbody>
</table>
</div>
</div>
</th:block>
<th:block th:unless="${#lists.isEmpty(model.variables)}">
<h2>Variables</h2>
<div class="table-responsive scroll-table table-card-body">
<div class="card">
<table class="table table-sm table-striped">
<thead>
<tr>
<th scope="col">Variable ID</th>
<th scope="col">Variable short name</th>
<th scope="col">Variable long name</th>
<th scope="col">Ontology name</th>
<th scope="col">Trait description</th>
</tr>
</thead>
<tbody>
<tr th:each="row : ${model.variables}">
<td>
<a th:unless="${#strings.isEmpty(row.documentationURL)}" th:href="${row.documentationURL}" th:text="${row.observationVariableDbId}" target="_blank" ></a>
<span th:if="${#strings.isEmpty(row.documentationURL)}" th:text="${row.observationVariableDbId}"></span>
</td>
<td th:text="${row.name}"></td>
<td th:text="${#lists.isEmpty(row.synonyms) ? '' : row.synonyms[0]}"></td>
<td th:text="${row.ontologyName}"></td>
<td th:text="${row.trait.description}"></td>
</tr>
</tbody>
</table>
</div>
</div>
</th:block>
<th:block th:unless="${#lists.isEmpty(model.trials)}">
<h2>Data Set</h2>
<div class="table-responsive scroll-big-table table-card-body">
<div class="card">
<table class="table table-sm table-striped">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Type</th>
<th scope="col">Linked studies identifier</th>
</tr>
</thead>
<tbody>
<tr th:each="row : ${model.trials}">
<td>
<a th:unless="${#strings.isEmpty(row.documentationURL)}" th:href="${row.documentationURL}" th:text="${row.trialName}" target="_blank" ></a>
<span th:if="${#strings.isEmpty(row.documentationURL)}" th:text="${row.trialName}"></span>
</td>
<td th:text="${row.trialType}"></td>
<td style="width: 60%">
<th:block th:each="trialStudy, iterStat : ${row.studies}"
th:if="${trialStudy.studyDbId != model.study.studyDbId}">
<a th:href="@{/studies/{studyId}(studyId=${trialStudy.studyDbId})}"
th:text="${trialStudy.studyName.trim()}">
</a><th:block th:if="${iterStat.last}">; </th:block>
</th:block>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</th:block>
<th:block th:unless="${#lists.isEmpty(model.study.contacts)}">
<h2>Contact</h2>
<div class="table-responsive scroll-table table-card-body">
<div class="card">
<table class="table table-sm table-striped">
<thead>
<tr>
<th scope="col">Role</th>
<th scope="col">Name</th>
<th scope="col">Email</th>
<th scope="col">Institution</th>
</tr>
</thead>
<tbody>
<tr th:each="row : ${model.study.contacts}">
<td th:text="${row.type}"></td>
<td th:text="${row.name}"></td>
<td th:text="${row.email}"></td>
<td th:text="${row.institutionName}"></td>
</tr>
</tbody>
</table>
</div>
</div>
</th:block>
<th:block th:unless="${#lists.isEmpty(model.additionalInfoProperties)}">
<h2>Additional information</h2>
<div class="table-responsive scroll-table table-card-body">
<div class="card">
<table class="table table-sm table-striped">
<tbody>
<tr th:each="row : ${model.additionalInfoProperties}">
<td style="width: 50%;" th:text="${row.key}"></td>
<td th:text="${row.value}"></td>
</tr>
</tbody>
</table>
</div>
</div>
</th:block>
<div th:replace="fragments/xrefs::xrefs(crossReferences=${model.crossReferences})"></div>
</main>
</body>
</html>
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