Skip to content

Commit

Permalink
Merge pull request #626 from ODM2/develop
Browse files Browse the repository at this point in the history
Release 0.14
  • Loading branch information
ptomasula authored Sep 2, 2022
2 parents d0b3049 + 4da1d98 commit b11ce92
Show file tree
Hide file tree
Showing 54 changed files with 3,732 additions and 248 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,4 @@ docker-compose.yml
/src/WebSDL/WebSDL/settings/settings.json
settings.json
settings.*.json
src/odm2/modelcache.pkl
3 changes: 2 additions & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ dependencies:
- django-cprofile-middleware
#used for unicode_compatiblity
#should confirm if this is still a dependency
- django-utils-six
- django-utils-six
- django-formtools
5 changes: 4 additions & 1 deletion src/WebSDL/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
'dataloaderinterface.apps.DataloaderinterfaceConfig',
'hydroshare',
'leafpack',
'streamwatch',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
Expand All @@ -60,7 +61,9 @@
'widget_tweaks',
'requests',
'reset_migrations',
'timeseries_visualization'
'timeseries_visualization',
'formtools',

]

MIDDLEWARE = [
Expand Down
76 changes: 32 additions & 44 deletions src/dataloaderinterface/ajax.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import json
from tkinter import E
from typing import List, Dict, Any

#PRT - temporarily avoiding the Django models because there appears to be a mismatch for the foreign key
#from dataloaderinterface.models import SensorMeasurement, SiteSensor
#SiteSensor -> odm2.results
#SensorMeasurement -> odm2.resulttimeseries
from odm2 import odm2datamodels
odm2_engine = odm2datamodels.odm2_engine
models = odm2datamodels.models

from odm2 import Session
from odm2 import engine as _db_engine
from odm2.models.core import SamplingFeatures, Variables, FeatureActions, Units, Results
from odm2.models.results import TimeSeriesResultValues

import sqlalchemy as sqla
import sqlalchemy
from sqlalchemy.sql import func
import pandas as pd
import datetime
Expand All @@ -26,35 +18,33 @@ def get_result_timeseries(request_data:Dict[str,Any]) -> str:
end_date = request_data['end_date'] if 'end_date' in request_data.keys() else None
if end_date: end_date = datetime.datetime.fromisoformat(end_date.rstrip('Z'))

query = sqlalchemy.select(models.TimeSeriesResultValues.valueid,
models.TimeSeriesResultValues.datavalue,
models.TimeSeriesResultValues.valuedatetime,
models.TimeSeriesResultValues.valuedatetimeutcoffset).\
filter(models.TimeSeriesResultValues.resultid == resultid)
if interval is not None:
filter_args = [models.TimeSeriesResultValues.resultid == resultid]
subquery = sqlalchemy.select(func.max(models.TimeSeriesResultValues.valuedatetime)
- datetime.timedelta(days=interval)).\
filter(models.TimeSeriesResultValues.resultid == resultid).scalar_subquery()
filter_args.append(models.TimeSeriesResultValues.valuedatetime >= subquery)
query = query.filter(*filter_args).\
order_by(models.TimeSeriesResultValues.valuedatetime.asc())
elif start_date is not None and end_date is not None:
query = query.filter(models.TimeSeriesResultValues.valuedatetime >= start_date) \
.filter(models.TimeSeriesResultValues.valuedatetime <= end_date) \
.order_by(models.TimeSeriesResultValues.valuedatetime.asc())

with Session() as session:
filter_args = [TimeSeriesResultValues.resultid == resultid]
query = session.query(TimeSeriesResultValues.valueid,
TimeSeriesResultValues.datavalue,
TimeSeriesResultValues.valuedatetime,
TimeSeriesResultValues.valuedatetimeutcoffset).\
filter(TimeSeriesResultValues.resultid == resultid)
if interval is not None:
subquery = session.query(func.max(TimeSeriesResultValues.valuedatetime)
- datetime.timedelta(days=interval)).\
filter(TimeSeriesResultValues.resultid == resultid).scalar_subquery()
filter_args.append(TimeSeriesResultValues.valuedatetime >= subquery)
query = query.filter(*filter_args).\
order_by(TimeSeriesResultValues.valuedatetime.asc())
elif start_date is not None and end_date is not None:
query = query.filter(TimeSeriesResultValues.valuedatetime >= start_date) \
.filter(TimeSeriesResultValues.valuedatetime <= end_date) \
.order_by(TimeSeriesResultValues.valuedatetime.asc())

df = pd.read_sql(query.statement, session.bind)
df['valuedatetime'] = df['valuedatetime'] + pd.to_timedelta(df['valuedatetimeutcoffset'], unit='hours')

return df.to_json(orient=orient, default_handler=str)
df = odm2_engine.read_query(query, output_format='dataframe')
df['valuedatetime'] = df['valuedatetime'] + pd.to_timedelta(df['valuedatetimeutcoffset'], unit='hours')
return df.to_json(orient=orient, default_handler=str)

def get_sampling_feature_metadata(request_data:Dict[str,Any]) -> str:
sampling_feature_code = str(request_data['sampling_feature_code'])

with _db_engine.connect() as connection:
#TODO - we should convert this to models instead of raw SQL
with odm2_engine.session_maker() as session:
query = f"SELECT rs.resultid, rs.resultuuid, samplingfeaturecode, "\
"samplingfeaturename, sampledmediumcv, un.unitsabbreviation, "\
"un.unitsname, variablenamecv, variablecode, zlocation, " \
Expand All @@ -67,14 +57,12 @@ def get_sampling_feature_metadata(request_data:Dict[str,Any]) -> str:
f"LEFT JOIN odm2.timeseriesresults AS tsr ON tsr.resultid = rs.resultid " \
f"LEFT JOIN odm2.units AS untrs ON untrs.unitsid = tsr.zlocationunitsid "\
f"WHERE sf.samplingfeaturecode = '{sampling_feature_code}'; "
df = pd.read_sql(query, connection)
df = pd.read_sql(query, session.bind)
return df.to_json(orient='records', default_handler=str)

def get_sampling_features(request_data:Dict[str,Any]) -> str:
with Session() as session:
query = session.query(SamplingFeatures.samplingfeatureuuid,
SamplingFeatures.samplingfeaturecode,
SamplingFeatures.samplingfeaturename).\
order_by(SamplingFeatures.samplingfeaturecode)
df = pd.read_sql(query.statement, session.bind)
return df.to_json(orient='records', default_handler=str)
query = sqlalchemy.select(models.SamplingFeatures.samplingfeatureuuid,
models.SamplingFeatures.samplingfeaturecode,
models.SamplingFeatures.samplingfeaturename).\
order_by(models.SamplingFeatures.samplingfeaturecode)
return odm2_engine.read_query(query)
67 changes: 65 additions & 2 deletions src/dataloaderinterface/static/dataloaderinterface/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,26 @@ a:hover {
color: rgb(23, 190, 207);
}

.icon-dark-blue {
color: rgb(0, 53, 71);
}

.icon-medium-orange {
color: rgb(237, 139, 22);;
}

.icon-teal {
color: rgb(0, 94, 84);
}

.icon-brown-green {
color: rgb(133, 128, 1);
}

.icon-bright-red {
color: rgb(225, 82, 60);
}

.map-container {
height: 410px;
}
Expand Down Expand Up @@ -980,7 +1000,7 @@ i.material-icons.site-card-icon {
margin-bottom: 30px;
}

#new-result-button, #new-leaf-pack-btn {
#new-result-button, #new-leaf-pack-btn, #new-streamwatch-btn {
margin-left: 10px;
margin-bottom: -10px;
vertical-align: sub;
Expand Down Expand Up @@ -1226,6 +1246,21 @@ div#followedSites .mdl-card__menu {
width: 100px;
}

.form-streamwatch .field-table input[type="number"] {
width: 100%;
}

.form-streamwatch .num-input .num-field label {
width: 100%;
}

.field-table div.form-field {
padding-bottom: 2px;
padding-left: 5px;
padding-right: 5px;

}

.form-leafpack .fa {
margin-right: 4px;
}
Expand All @@ -1241,6 +1276,12 @@ div#followedSites .mdl-card__menu {
padding-bottom: 40px;
}

.form-leafpack .std-row {
margin-left: 20px;
padding-left: 20px;
padding-bottom: 40px;
}

.form-leafpack .step-icon {
font-size: 48px;
color: #048a8a;
Expand Down Expand Up @@ -1294,6 +1335,13 @@ td.label, p.label {
font-weight: 700;
}

td.block-label {
color: #66CCCC;
/* font-weight: 700; */
font-style: italic;
font-size: 15px
}

.form-leafpack .step-number {
display: inline-block;
border-radius: 50%;
Expand Down Expand Up @@ -1475,4 +1523,19 @@ i.file-icon {
box-shadow: none !important;
pointer-events: none !important;
cursor: default !important;
}
}

/* Detail Page Styling */
.block-label {
color: #66CCCC
}

/* StreamWatch Site Detail Summary Table */
.streamwatch-site-summary .mdl-data-table th{
text-align: center;
}

.streamwatch-site-summary .mdl-data-table td{
text-align: center;
}

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
function defaultExperimentsMessage() {
$("tr.no-experiments-row").toggleClass("hidden", !!$("tr.leafpack-form:not(.deleted-row)").length);
}

$(document).ready(function() {
$(".btn-delete-experiment").click(function () {
var experiment = $(this).parents('tr');
$('#confirm-delete-experiment').data('to-delete', experiment).modal('show');
});

$("#btn-confirm-delete-experiment").click(function () {
const dialog = $('#confirm-delete-experiment');
const row = dialog.data('to-delete');
$("#btn-confirm-delete-experiment").prop("disabled", true).text("DELETING ...");

const sampling_feature_code = $('#sampling_feature_code').attr('sampling_feature_code');

$.ajax({
url: `/sites/${sampling_feature_code}/streamwatch/delete/`,
type: 'post',
data: {
csrfmiddlewaretoken: $('fieldset.form-fieldset input[name="csrfmiddlewaretoken"]').val(),
id: row.data('id')
}
}).done(function (data, message, xhr) {
if (xhr.status === 202) {
// Valid
row.remove();
snackbarMsg('StreamWatch assessment has been deleted!');

} else if (xhr.status === 206) {
// Invalid
snackbarMsg('StreamWatch assessment could not be deleted!');
}
}).fail(function (xhr, error) {
console.log(error);
}).always(function (response, status, xhr) {
$("#btn-confirm-delete-experiment").prop("disabled", false).text("DELETE");
defaultExperimentsMessage();
dialog.modal('hide');
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Created by HTAO on 6/7/2022.
*/
$(document).ready(function () {
$('.datepicker').datepicker({
format: 'yyyy-mm-dd',
startDate: '0d'
});

// Validation for placement date
$('#id_placement_date, #id_retrieval_date').change(function () {
var placement = $('#id_placement_date').val();
var retrieval = $('#id_retrieval_date').val();
if (placement && retrieval) {
var placementDate = new Date(placement);
var retrievalDate = new Date(retrieval);
if (placementDate > retrievalDate) {
$('#id_placement_date')[0].setCustomValidity('Placement date has to be before the retrieval date.');
}
else {
$('#id_placement_date')[0].setCustomValidity('');
$('#id_retrieval_date')[0].setCustomValidity('');
}
}
else if (!$(this).val()) {
this.setCustomValidity('Please fill out this field.');
}
});

favorite =[];
//totalForms = $('#id_2_TOTAL_FORMS');
let totalForms = document.querySelector("#id_para-TOTAL_FORMS")
let sensorForm = document.querySelectorAll(".parameter-form")
let container = document.querySelector("#para-container")
let addButton = document.querySelector("#para-end")

let formNum = sensorForm.length-1 // Get the number of the last form on the page with zero-based indexing
//alert("My selected types are: " + favorite.join(", "));

$("input[name='0-activity_type']").click(function() {
favorite =[];
$.each($("input[name='0-activity_type']:checked"), function(){
favorite.push($(this).val());
});
//alert("My selected types are: " + favorite.join(", "));
});

$("form").submit(function() {
// favorite =[];
// $.each($("input[name='0-activity_type']:checked"), function(){
// favorite.push($(this).val());
// });
//alert("My selected types are: " + favorite.join(", "));
});

$("#id_sensor-test_method").change(function() {
//alert("My selected types are: " + $(this).find(":selected").text());

if($(this).find(":selected").text()!="Meter") { //3rd radiobutton
$("#id_sensor-calibration_date").attr("disabled", "disabled");
$("#id_sensor-meter").attr("disabled", "disabled");
}
else {
$("#id_sensor-calibration_date").removeAttr("disabled");
$("#id_sensor-meter").removeAttr("disabled");
}

});

$(".btn-add-parameter").click(function(){
//alert("Add method clicked!");
AddSensorParameterForm();
});


// tutorial for dynamically adding Forms in Django with Formsets and JavaScript
// https://www.brennantymrak.com/articles/django-dynamic-formsets-javascript

function AddSensorParameterForm() {
//e.preventDefault()

const newForm = sensorForm[0].cloneNode(true) //Clone the bird form
$(newForm).attr('class','row parameter-form');
let formRegex = RegExp(`parameter-(\\d){1}-`,'g') //Regex to find all instances of the form number

formNum++ //Increment the form number
newForm.innerHTML = newForm.innerHTML.replace(formRegex, `para-${formNum}-`) //Update the new form to have the correct form number

//container.insertBefore(newForm, addButton) //Insert the new form at the end of the list of forms
//$(newForm).insertBefore( "#btn-add-parameter" );
$(newForm).val('');
$('.parameter-card').append($(newForm));

totalForms.setAttribute('value', `${formNum+1}`) //Increment the number of total forms in the management form

}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
$(document).ready(function () {

$( "#accordion" ).accordion();


});
Loading

0 comments on commit b11ce92

Please sign in to comment.