Stats chart is now operational.
This commit is contained in:
parent
56f8c19520
commit
498478b577
@ -5,6 +5,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
|
||||
/**
|
||||
@ -28,7 +29,7 @@ public class AverageStatsChartJs {
|
||||
teamwork = new ArrayList<>(),
|
||||
knowledge = new ArrayList<>();
|
||||
for(AverageStats averageStats: inputData){
|
||||
labels.add(averageStats.getDate().toString());
|
||||
labels.add(averageStats.getDate().toString("yyyy-MM-dd"));
|
||||
monitoring.add(averageStats.getMonitoring());
|
||||
control.add(averageStats.getControl());
|
||||
conservatism.add(averageStats.getConservatism());
|
||||
@ -42,7 +43,6 @@ public class AverageStatsChartJs {
|
||||
datasets.add(new Dataset("Knowledge", "#000", knowledge));
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
class Dataset {
|
||||
@NonNull
|
||||
@JsonProperty
|
||||
@ -52,8 +52,22 @@ public class AverageStatsChartJs {
|
||||
@JsonProperty
|
||||
private final String backgroundColor;
|
||||
|
||||
@NonNull
|
||||
@JsonProperty
|
||||
private final String borderColor;
|
||||
|
||||
@NonNull
|
||||
@JsonProperty
|
||||
private final List<Double> data;
|
||||
|
||||
@JsonProperty
|
||||
private final boolean fill = false;
|
||||
|
||||
Dataset(String label, String color, List<Double> data){
|
||||
this.label = label;
|
||||
this.backgroundColor = color;
|
||||
this.borderColor = color;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,18 @@ package uk.co.neviyn.Observations.dao;
|
||||
|
||||
import io.dropwizard.hibernate.AbstractDAO;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.query.Query;
|
||||
import org.joda.time.DateTime;
|
||||
import uk.co.neviyn.Observations.api.AverageStats;
|
||||
import uk.co.neviyn.Observations.core.Observation;
|
||||
import uk.co.neviyn.Observations.core.Site;
|
||||
import uk.co.neviyn.Observations.core.Tutor;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ObservationDao extends AbstractDAO<Observation> {
|
||||
@ -25,16 +33,27 @@ public class ObservationDao extends AbstractDAO<Observation> {
|
||||
return currentSession().createQuery("from Observation", Observation.class).list();
|
||||
}
|
||||
|
||||
public List<AverageStats> averageStatsForAll(){
|
||||
final String hql = "select new uk.co.neviyn.Observations.api.AverageStats(avg(obs.monitoring), avg(obs.control), avg(obs.conservatism), " +
|
||||
"avg(obs.teamwork), avg(obs.knowledge), obs.date) from Observation obs group by obs.date order by obs.date";
|
||||
return currentSession().createQuery(hql, AverageStats.class).list();
|
||||
}
|
||||
|
||||
public List<AverageStats> averageStatsForSite(Site site){
|
||||
final String hql = "select new uk.co.neviyn.Observations.api.AverageStats(avg(obs.monitoring), avg(obs.control), avg(obs.conservatism)," +
|
||||
"avg(obs.teamwork), avg(obs.knowledge), obs.date) from Observation obs where obs.site = :site " +
|
||||
"group by obs.date order by obs.date";
|
||||
return currentSession().createQuery(hql, AverageStats.class).setParameter("site", site).list();
|
||||
// TODO: Add tutor filter
|
||||
public List<AverageStats> averageStats(Site site, Tutor tutor, DateTime startDate, DateTime endDate, String whom){
|
||||
CriteriaBuilder builder = currentSession().getCriteriaBuilder();
|
||||
CriteriaQuery<AverageStats> criteriaQuery = builder.createQuery(AverageStats.class);
|
||||
Root<Observation> root = criteriaQuery.from(Observation.class);
|
||||
criteriaQuery.multiselect(builder.avg(root.get("monitoring")), builder.avg(root.get("control")),
|
||||
builder.avg(root.get("conservatism")), builder.avg(root.get("teamwork")), builder.avg(root.get("knowledge")),
|
||||
root.get("date"));
|
||||
criteriaQuery.groupBy(root.get("date"));
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
if(site != null)
|
||||
predicates.add(builder.equal(root.get("site"), site));
|
||||
if(startDate != null)
|
||||
predicates.add(builder.greaterThanOrEqualTo(root.get("date"), startDate));
|
||||
if(endDate != null)
|
||||
predicates.add(builder.lessThanOrEqualTo(root.get("date"), endDate));
|
||||
if(whom != null)
|
||||
predicates.add(builder.equal(root.get("whom"), whom));
|
||||
criteriaQuery.having(predicates.toArray(new Predicate[0]));
|
||||
Query<AverageStats> query = currentSession().createQuery(criteriaQuery);
|
||||
System.out.println(query.getQueryString());
|
||||
return query.getResultList();
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import uk.co.neviyn.Observations.api.AverageStats;
|
||||
import uk.co.neviyn.Observations.api.AverageStatsChartJs;
|
||||
import uk.co.neviyn.Observations.api.NewObservation;
|
||||
import uk.co.neviyn.Observations.core.Observation;
|
||||
@ -16,12 +15,10 @@ import uk.co.neviyn.Observations.dao.ObservationDao;
|
||||
import uk.co.neviyn.Observations.dao.SiteDao;
|
||||
import uk.co.neviyn.Observations.dao.TutorDao;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@ -58,32 +55,28 @@ public class ObservationResource {
|
||||
return observation.getId();
|
||||
}
|
||||
|
||||
@Path("/average/all")
|
||||
@Path("/average")
|
||||
@GET
|
||||
@UnitOfWork
|
||||
public List<AverageStats> averageObservationScores() {
|
||||
return dao.averageStatsForAll();
|
||||
}
|
||||
|
||||
@Path("/average/all/chartjs")
|
||||
@GET
|
||||
@UnitOfWork
|
||||
public AverageStatsChartJs averageStatsChartJs() {
|
||||
return new AverageStatsChartJs(averageObservationScores());
|
||||
}
|
||||
|
||||
@Path("/average/{id}")
|
||||
@GET
|
||||
@UnitOfWork
|
||||
public List<AverageStats> averageObservationScoresForSite(@PathParam("id") long siteId) {
|
||||
Site site = siteDao.get(siteId);
|
||||
return dao.averageStatsForSite(site);
|
||||
}
|
||||
|
||||
@Path("/average/{id}/chartjs")
|
||||
@GET
|
||||
@UnitOfWork
|
||||
public AverageStatsChartJs averageObservationScoresForSiteChartJs(@PathParam("id") long siteId) {
|
||||
return new AverageStatsChartJs(averageObservationScoresForSite(siteId));
|
||||
public AverageStatsChartJs averageObservationScores(@QueryParam("site") Integer siteId, @QueryParam("tutor") Integer tutorId,
|
||||
@QueryParam("startDate") String startDate,
|
||||
@QueryParam("endDate") String endDate, @QueryParam("whom") String whom) {
|
||||
Site site = null;
|
||||
Tutor tutor = null;
|
||||
DateTime start = null;
|
||||
DateTime end = null;
|
||||
try{
|
||||
site = siteDao.get(siteId);
|
||||
} catch (Exception ignored){}
|
||||
try{
|
||||
tutor = tutorDao.get(tutorId);
|
||||
} catch (Exception ignored){}
|
||||
try{
|
||||
start = DateTime.parse(startDate);
|
||||
} catch (Exception ignored){}
|
||||
try{
|
||||
end = DateTime.parse(endDate);
|
||||
} catch (Exception ignored) {}
|
||||
return new AverageStatsChartJs(dao.averageStats(site, tutor, start, end, whom));
|
||||
}
|
||||
}
|
||||
|
@ -64,20 +64,20 @@ public class ObservationDaoTest extends DaoTestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void averageStatsForAll() {
|
||||
public void averageStatsNoParam() {
|
||||
Observation otherEntry = SerializationUtils.clone(observation);
|
||||
otherEntry.setMonitoring(5);
|
||||
otherEntry.setControl(5);
|
||||
otherEntry.setConservatism(5);
|
||||
otherEntry.setTeamwork(5);
|
||||
Observation differentDay = SerializationUtils.clone(observation);
|
||||
differentDay.setDate(DateTime.now());
|
||||
differentDay.setDate(DateTime.parse("2018-09-20"));
|
||||
testRule.inTransaction(() -> {
|
||||
dao.persist(observation);
|
||||
dao.persist(otherEntry);
|
||||
dao.persist(differentDay);
|
||||
});
|
||||
List<AverageStats> stats = dao.averageStatsForAll();
|
||||
List<AverageStats> stats = dao.averageStats(null, null, null, null, null);
|
||||
assertNotNull(stats);
|
||||
assertEquals(2, stats.size());
|
||||
final AverageStats statObject = stats.get(0);
|
||||
@ -89,26 +89,22 @@ public class ObservationDaoTest extends DaoTestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void averageStatsForSite() {
|
||||
public void averageStatsWithSite() {
|
||||
Observation otherEntry = SerializationUtils.clone(observation);
|
||||
otherEntry.setMonitoring(5);
|
||||
otherEntry.setControl(5);
|
||||
otherEntry.setConservatism(5);
|
||||
otherEntry.setTeamwork(5);
|
||||
|
||||
|
||||
Observation hiddenEntity = SerializationUtils.clone(observation);
|
||||
Site hiddenSite = Site.builder().name("Area 51").build();
|
||||
hiddenEntity.setSite(hiddenSite);
|
||||
Observation differentDay = SerializationUtils.clone(observation);
|
||||
differentDay.setDate(DateTime.parse("2018-09-20"));
|
||||
testRule.inTransaction(() -> {
|
||||
dao.persist(observation);
|
||||
dao.persist(otherEntry);
|
||||
siteDao.persist(hiddenSite);
|
||||
dao.persist(hiddenEntity);
|
||||
dao.persist(differentDay);
|
||||
});
|
||||
List<AverageStats> stats = dao.averageStatsForSite(site);
|
||||
List<AverageStats> stats = dao.averageStats(site, null, null, null, null);
|
||||
assertNotNull(stats);
|
||||
assertEquals(1, stats.size());
|
||||
assertEquals(2, stats.size());
|
||||
final AverageStats statObject = stats.get(0);
|
||||
assertEquals(3, statObject.getMonitoring(), 0);
|
||||
assertEquals(3.5, statObject.getControl(), 0);
|
||||
@ -116,4 +112,108 @@ public class ObservationDaoTest extends DaoTestBase {
|
||||
assertEquals(4.5, statObject.getTeamwork(), 0);
|
||||
assertEquals(5, statObject.getKnowledge(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void averageStatsWithStartDate() {
|
||||
Observation otherEntry = SerializationUtils.clone(observation);
|
||||
otherEntry.setMonitoring(5);
|
||||
otherEntry.setControl(5);
|
||||
otherEntry.setConservatism(5);
|
||||
otherEntry.setTeamwork(5);
|
||||
Observation differentDay = SerializationUtils.clone(observation);
|
||||
differentDay.setDate(DateTime.parse("2018-09-20"));
|
||||
testRule.inTransaction(() -> {
|
||||
dao.persist(observation);
|
||||
dao.persist(otherEntry);
|
||||
dao.persist(differentDay);
|
||||
});
|
||||
List<AverageStats> stats = dao.averageStats(null, null, DateTime.parse("2018-09-01").withTimeAtStartOfDay(), null, null);
|
||||
assertNotNull(stats);
|
||||
assertEquals(2, stats.size());
|
||||
// Change one observation to outside range
|
||||
differentDay.setDate(DateTime.parse("2018-08-20"));
|
||||
testRule.inTransaction(() -> {
|
||||
dao.persist(differentDay);
|
||||
});
|
||||
stats = dao.averageStats(null, null, DateTime.parse("2018-09-01").withTimeAtStartOfDay(), null, null);
|
||||
assertNotNull(stats);
|
||||
assertEquals(1, stats.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void averageStatsWithEndDate() {
|
||||
Observation otherEntry = SerializationUtils.clone(observation);
|
||||
otherEntry.setMonitoring(5);
|
||||
otherEntry.setControl(5);
|
||||
otherEntry.setConservatism(5);
|
||||
otherEntry.setTeamwork(5);
|
||||
Observation differentDay = SerializationUtils.clone(observation);
|
||||
differentDay.setDate(DateTime.parse("2018-09-20"));
|
||||
testRule.inTransaction(() -> {
|
||||
dao.persist(observation);
|
||||
dao.persist(otherEntry);
|
||||
dao.persist(differentDay);
|
||||
});
|
||||
List<AverageStats> stats = dao.averageStats(null, null, null, DateTime.parse("2018-10-01").withTimeAtStartOfDay(), null);
|
||||
assertNotNull(stats);
|
||||
assertEquals(2, stats.size());
|
||||
// Change one observation to outside range
|
||||
differentDay.setDate(DateTime.parse("2018-10-20"));
|
||||
testRule.inTransaction(() -> {
|
||||
dao.persist(differentDay);
|
||||
});
|
||||
stats = dao.averageStats(null, null, null, DateTime.parse("2018-10-01").withTimeAtStartOfDay(), null);
|
||||
assertNotNull(stats);
|
||||
assertEquals(1, stats.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void averageStatsWithBothDate() {
|
||||
Observation otherEntry = SerializationUtils.clone(observation);
|
||||
otherEntry.setMonitoring(5);
|
||||
otherEntry.setControl(5);
|
||||
otherEntry.setConservatism(5);
|
||||
otherEntry.setTeamwork(5);
|
||||
otherEntry.setDate(DateTime.parse("2018-08-20"));
|
||||
Observation differentDay = SerializationUtils.clone(observation);
|
||||
differentDay.setDate(DateTime.parse("2018-10-20"));
|
||||
testRule.inTransaction(() -> {
|
||||
dao.persist(observation);
|
||||
dao.persist(otherEntry);
|
||||
dao.persist(differentDay);
|
||||
});
|
||||
List<AverageStats> stats = dao.averageStats(site, null, null, null, null);
|
||||
assertNotNull(stats);
|
||||
assertEquals(3, stats.size());
|
||||
stats = dao.averageStats(null, null, DateTime.parse("2018-09-01").withTimeAtStartOfDay(), DateTime.parse("2018-10-01").withTimeAtStartOfDay(), null);
|
||||
assertNotNull(stats);
|
||||
System.out.println(stats.toString());
|
||||
assertEquals(1, stats.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void averageStatsWithWhom() {
|
||||
Observation otherEntry = SerializationUtils.clone(observation);
|
||||
otherEntry.setMonitoring(5);
|
||||
otherEntry.setControl(5);
|
||||
otherEntry.setConservatism(5);
|
||||
otherEntry.setTeamwork(5);
|
||||
Observation differentDay = SerializationUtils.clone(observation);
|
||||
differentDay.setDate(DateTime.parse("2018-09-20"));
|
||||
testRule.inTransaction(() -> {
|
||||
dao.persist(observation);
|
||||
dao.persist(otherEntry);
|
||||
dao.persist(differentDay);
|
||||
});
|
||||
List<AverageStats> stats = dao.averageStats(null, null, null, null, "Group A");
|
||||
assertNotNull(stats);
|
||||
assertEquals(2, stats.size());
|
||||
differentDay.setWhom("Group B");
|
||||
testRule.inTransaction(() -> {
|
||||
dao.persist(differentDay);
|
||||
});
|
||||
stats = dao.averageStats(null, null, null, null, "Group A");
|
||||
assertNotNull(stats);
|
||||
assertEquals(1, stats.size());
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
<script>
|
||||
import { Line } from "vue-chartjs";
|
||||
import { Line, mixins } from "vue-chartjs";
|
||||
|
||||
export default {
|
||||
extends: Line,
|
||||
props: ["data", "options"],
|
||||
mixins: [mixins.reactiveProp],
|
||||
props: ["chartData", "options"],
|
||||
mounted() {
|
||||
this.renderChart(this.data, this.options);
|
||||
this.renderChart(this.chartData, this.options);
|
||||
}
|
||||
};
|
||||
</script>
|
@ -17,47 +17,101 @@
|
||||
<b-form-select v-model="siteSelection" :options="siteOptions" style="text-align:center;" />
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-form-group label="Who">
|
||||
<b-form-input v-model="whom" type="text" style="text-align:center;"></b-form-input>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-form-group label="From">
|
||||
<date-picker v-model="startDate" :config="dateOptions" />
|
||||
<date-picker v-model="startDate" @dp-change="changeStartDate" value="startDate" :config="dateOptions" />
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-form-group label="To">
|
||||
<date-picker v-model="endDate" :config="dateOptions" />
|
||||
<date-picker v-model="endDate" @dp-change="changeEndDate" value="endDate" :config="dateOptions" />
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-button v-on:click="getFilteredAverage()">Refresh</b-button>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row>
|
||||
<b-col>
|
||||
<stats-view v-if="chartData != null && chartData != {}" v-bind:chartData="chartData" :options="options" />
|
||||
</b-col>
|
||||
</b-row>
|
||||
<stats-view v-if="chartData != null && chartData != {}" :data="chartData" :options="options" />
|
||||
</b-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from "vue";
|
||||
import StatsView from "../components/StatsView";
|
||||
var moment = require("moment");
|
||||
export default {
|
||||
name: "stats",
|
||||
components: { StatsView },
|
||||
data: function() {
|
||||
return {
|
||||
chartData: null,
|
||||
options: null,
|
||||
options: {
|
||||
responsive: true,
|
||||
tooltips: {
|
||||
mode: "index",
|
||||
intersect: false
|
||||
},
|
||||
hover: {
|
||||
mode: "nearest",
|
||||
intersect: true
|
||||
},
|
||||
scales: {
|
||||
xAxes: [
|
||||
{
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: "Date"
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: "Average Score"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
errorStatus: null,
|
||||
errorMessage: null,
|
||||
startDate: new Date(),
|
||||
endDate: new Date(),
|
||||
startDate: moment().subtract(7, "days"),
|
||||
endDate: moment(),
|
||||
dateOptions: {
|
||||
format: "DD/MM/YYYY",
|
||||
useCurrent: false
|
||||
},
|
||||
siteSelection: null,
|
||||
siteOptions: null
|
||||
siteOptions: [],
|
||||
tutorSelection: null,
|
||||
tutorOptions: null,
|
||||
whom: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getAllTimeAverage: function() {
|
||||
getFilteredAverage: function() {
|
||||
Vue.axios
|
||||
.get("/observation/average/all/chartjs")
|
||||
.get("/observation/average", {
|
||||
params: {
|
||||
site: this.siteSelection,
|
||||
tutor: this.tutorSelection,
|
||||
startDate: moment(this.startDate).format("YYYY-MM-DD"),
|
||||
endDate: moment(this.endDate).format("YYYY-MM-DD"),
|
||||
whom: this.whom
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.chartData = response.data;
|
||||
})
|
||||
@ -66,15 +120,36 @@ export default {
|
||||
this.errorMessage = error.response.data;
|
||||
this.$refs.errorModal.show();
|
||||
});
|
||||
},
|
||||
getTutors: function() {
|
||||
if (this.siteSelection != null) {
|
||||
Vue.axios
|
||||
.get("/site/" + this.siteSelection + "/tutors")
|
||||
.then(response => {
|
||||
this.tutorOptions = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
changeStartDate: function(e) {
|
||||
this.startDate = e.date;
|
||||
},
|
||||
changeEndDate: function(e) {
|
||||
this.endDate = e.date;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
siteSelection: function() {
|
||||
this.tutorOptions = null;
|
||||
this.tutorSelection = null;
|
||||
this.getTutors();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getAllTimeAverage();
|
||||
this.getFilteredAverage();
|
||||
Vue.axios
|
||||
.get("/site/all")
|
||||
.then(response => {
|
||||
this.siteOptions = response.data;
|
||||
this.loaded = true;
|
||||
})
|
||||
.catch(error => {
|
||||
this.errorStatus = error.response.status;
|
||||
|
Loading…
Reference in New Issue
Block a user