mirror of
https://github.com/bckelley/cgm-remote-monitor.git
synced 2026-08-24 03:14:12 -05:00
feat: validate temp target in Careportal (#4812)
* Adds data validation function to the careportal * Validate temporary targets define both low and high target and sanitize the values for obvious issues * Removes unused logging from openaps pill * Fixes a bug with undefined setting
This commit is contained in:
+136
-71
@@ -7,7 +7,7 @@ var times = require('../times');
|
||||
var Storages = require('js-storage');
|
||||
|
||||
function init (client, $) {
|
||||
var careportal = { };
|
||||
var careportal = {};
|
||||
|
||||
var translate = client.translate;
|
||||
var storage = Storages.localStorage;
|
||||
@@ -18,7 +18,7 @@ function init (client, $) {
|
||||
careportal.events = _.map(careportal.allEventTypes, function each (event) {
|
||||
return _.pick(event, ['val', 'name']);
|
||||
});
|
||||
|
||||
|
||||
var eventTime = $('#eventTimeValue');
|
||||
var eventDate = $('#eventDateValue');
|
||||
|
||||
@@ -28,11 +28,11 @@ function init (client, $) {
|
||||
eventDate.val(time.format('YYYY-MM-DD'));
|
||||
}
|
||||
|
||||
function mergeDateAndTime ( ) {
|
||||
function mergeDateAndTime () {
|
||||
return client.utils.mergeInputTime(eventTime.val(), eventDate.val());
|
||||
}
|
||||
|
||||
function updateTime(ele, time) {
|
||||
function updateTime (ele, time) {
|
||||
ele.attr('oldminutes', time.minutes());
|
||||
ele.attr('oldhours', time.hours());
|
||||
}
|
||||
@@ -49,9 +49,9 @@ function init (client, $) {
|
||||
inputMatrix[event.val] = _.pick(event, ['bg', 'insulin', 'carbs', 'protein', 'fat', 'prebolus', 'duration', 'percent', 'absolute', 'profile', 'split', 'reasons', 'targets']);
|
||||
});
|
||||
|
||||
careportal.filterInputs = function filterInputs ( event ) {
|
||||
careportal.filterInputs = function filterInputs (event) {
|
||||
var eventType = $('#eventType').val();
|
||||
|
||||
|
||||
function displayType (enabled) {
|
||||
if (enabled) {
|
||||
return '';
|
||||
@@ -59,28 +59,28 @@ function init (client, $) {
|
||||
return 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function resetIfHidden(visible, id) {
|
||||
|
||||
function resetIfHidden (visible, id) {
|
||||
if (!visible) {
|
||||
$(id).val('');
|
||||
}
|
||||
}
|
||||
|
||||
var reasons = inputMatrix[eventType]['reasons'];
|
||||
$('#reasonLabel').css('display',displayType(reasons && reasons.length > 0));
|
||||
$('#targets').css('display',displayType(inputMatrix[eventType]['targets']));
|
||||
$('#reasonLabel').css('display', displayType(reasons && reasons.length > 0));
|
||||
$('#targets').css('display', displayType(inputMatrix[eventType]['targets']));
|
||||
|
||||
$('#bg').css('display',displayType(inputMatrix[eventType]['bg']));
|
||||
$('#insulinGivenLabel').css('display',displayType(inputMatrix[eventType]['insulin']));
|
||||
$('#carbsGivenLabel').css('display',displayType(inputMatrix[eventType]['carbs']));
|
||||
$('#proteinGivenLabel').css('display',displayType(inputMatrix[eventType]['protein']));
|
||||
$('#fatGivenLabel').css('display',displayType(inputMatrix[eventType]['fat']));
|
||||
$('#durationLabel').css('display',displayType(inputMatrix[eventType]['duration']));
|
||||
$('#percentLabel').css('display',displayType(inputMatrix[eventType]['percent'] && $('#absolute').val() === ''));
|
||||
$('#absoluteLabel').css('display',displayType(inputMatrix[eventType]['absolute'] && $('#percent').val() === ''));
|
||||
$('#profileLabel').css('display',displayType(inputMatrix[eventType]['profile']));
|
||||
$('#preBolusLabel').css('display',displayType(inputMatrix[eventType]['prebolus']));
|
||||
$('#insulinSplitLabel').css('display',displayType(inputMatrix[eventType]['split']));
|
||||
$('#bg').css('display', displayType(inputMatrix[eventType]['bg']));
|
||||
$('#insulinGivenLabel').css('display', displayType(inputMatrix[eventType]['insulin']));
|
||||
$('#carbsGivenLabel').css('display', displayType(inputMatrix[eventType]['carbs']));
|
||||
$('#proteinGivenLabel').css('display', displayType(inputMatrix[eventType]['protein']));
|
||||
$('#fatGivenLabel').css('display', displayType(inputMatrix[eventType]['fat']));
|
||||
$('#durationLabel').css('display', displayType(inputMatrix[eventType]['duration']));
|
||||
$('#percentLabel').css('display', displayType(inputMatrix[eventType]['percent'] && $('#absolute').val() === ''));
|
||||
$('#absoluteLabel').css('display', displayType(inputMatrix[eventType]['absolute'] && $('#percent').val() === ''));
|
||||
$('#profileLabel').css('display', displayType(inputMatrix[eventType]['profile']));
|
||||
$('#preBolusLabel').css('display', displayType(inputMatrix[eventType]['prebolus']));
|
||||
$('#insulinSplitLabel').css('display', displayType(inputMatrix[eventType]['split']));
|
||||
|
||||
$('#reason').empty();
|
||||
_.each(reasons, function eachReason (reason) {
|
||||
@@ -103,7 +103,7 @@ function init (client, $) {
|
||||
maybePrevent(event);
|
||||
};
|
||||
|
||||
careportal.reasonable = function reasonable ( ) {
|
||||
careportal.reasonable = function reasonable () {
|
||||
var eventType = $('#eventType').val();
|
||||
var reasons = inputMatrix[eventType]['reasons'];
|
||||
var selected = $('#reason').val();
|
||||
@@ -133,10 +133,10 @@ function init (client, $) {
|
||||
}
|
||||
};
|
||||
|
||||
careportal.prepareEvents = function prepareEvents ( ) {
|
||||
careportal.prepareEvents = function prepareEvents () {
|
||||
$('#eventType').empty();
|
||||
_.each(careportal.events, function eachEvent(event) {
|
||||
$('#eventType').append('<option value="' + event.val+ '">' + translate(event.name) + '</option>');
|
||||
_.each(careportal.events, function eachEvent (event) {
|
||||
$('#eventType').append('<option value="' + event.val + '">' + translate(event.name) + '</option>');
|
||||
});
|
||||
$('#eventType').change(careportal.filterInputs);
|
||||
$('#reason').change(careportal.reasonable);
|
||||
@@ -148,7 +148,7 @@ function init (client, $) {
|
||||
careportal.adjustSplit();
|
||||
};
|
||||
|
||||
careportal.adjustSplit = function adjustSplit(event) {
|
||||
careportal.adjustSplit = function adjustSplit (event) {
|
||||
if ($(this).attr('id') === 'insulinSplitNow') {
|
||||
var nowval = parseInt($('#insulinSplitNow').val()) || 0;
|
||||
$('#insulinSplitExt').val(100 - nowval);
|
||||
@@ -158,12 +158,12 @@ function init (client, $) {
|
||||
$('#insulinSplitNow').val(100 - extval);
|
||||
$('#insulinSplitExt').val(extval);
|
||||
}
|
||||
|
||||
|
||||
maybePrevent(event);
|
||||
};
|
||||
|
||||
careportal.resolveEventName = function resolveEventName(value) {
|
||||
_.each(careportal.events, function eachEvent(e) {
|
||||
|
||||
careportal.resolveEventName = function resolveEventName (value) {
|
||||
_.each(careportal.events, function eachEvent (e) {
|
||||
if (e.val === value) {
|
||||
value = e.name;
|
||||
}
|
||||
@@ -171,9 +171,9 @@ function init (client, $) {
|
||||
return value;
|
||||
};
|
||||
|
||||
careportal.prepare = function prepare ( ) {
|
||||
careportal.prepare = function prepare () {
|
||||
$('#profile').empty();
|
||||
client.profilefunctions.listBasalProfiles().forEach(function (p) {
|
||||
client.profilefunctions.listBasalProfiles().forEach(function(p) {
|
||||
$('#profile').append('<option val="' + p + '">' + p + '</option>');
|
||||
});
|
||||
careportal.prepareEvents();
|
||||
@@ -195,31 +195,31 @@ function init (client, $) {
|
||||
setDateAndTime();
|
||||
};
|
||||
|
||||
function gatherData ( ) {
|
||||
function gatherData () {
|
||||
var data = {
|
||||
enteredBy: $('#enteredBy').val()
|
||||
, eventType: $('#eventType').val()
|
||||
, glucose: $('#glucoseValue').val().replace(',','.')
|
||||
, reason: $('#reason').val()
|
||||
, targetTop: $('#targetTop').val().replace(',','.')
|
||||
, targetBottom: $('#targetBottom').val().replace(',','.')
|
||||
, glucoseType: $('#treatment-form').find('input[name=glucoseType]:checked').val()
|
||||
, carbs: $('#carbsGiven').val()
|
||||
, protein: $('#proteinGiven').val()
|
||||
, fat: $('#fatGiven').val()
|
||||
, insulin: $('#insulinGiven').val()
|
||||
, duration: times.msecs(parse_duration($('#duration').val())).mins < 1 ? $('#duration').val() : times.msecs(parse_duration($('#duration').val())).mins
|
||||
, percent: $('#percent').val()
|
||||
, profile: $('#profile').val()
|
||||
, preBolus: parseInt($('#preBolus').val())
|
||||
, notes: $('#notes').val()
|
||||
, units: client.settings.units
|
||||
, eventType: $('#eventType').val()
|
||||
, glucose: $('#glucoseValue').val().replace(',', '.')
|
||||
, reason: $('#reason').val()
|
||||
, targetTop: $('#targetTop').val().replace(',', '.')
|
||||
, targetBottom: $('#targetBottom').val().replace(',', '.')
|
||||
, glucoseType: $('#treatment-form').find('input[name=glucoseType]:checked').val()
|
||||
, carbs: $('#carbsGiven').val()
|
||||
, protein: $('#proteinGiven').val()
|
||||
, fat: $('#fatGiven').val()
|
||||
, insulin: $('#insulinGiven').val()
|
||||
, duration: times.msecs(parse_duration($('#duration').val())).mins < 1 ? $('#duration').val() : times.msecs(parse_duration($('#duration').val())).mins
|
||||
, percent: $('#percent').val()
|
||||
, profile: $('#profile').val()
|
||||
, preBolus: parseInt($('#preBolus').val())
|
||||
, notes: $('#notes').val()
|
||||
, units: client.settings.units
|
||||
};
|
||||
|
||||
if (units == "mmol") {
|
||||
data.targetTop = data.targetTop * 18;
|
||||
data.targetBottom = data.targetBottom * 18;
|
||||
}
|
||||
if (units == "mmol") {
|
||||
data.targetTop = data.targetTop * 18;
|
||||
data.targetBottom = data.targetBottom * 18;
|
||||
}
|
||||
|
||||
//special handling for absolute to support temp to 0
|
||||
var absolute = $('#absolute').val();
|
||||
@@ -230,7 +230,7 @@ function init (client, $) {
|
||||
if ($('#othertime').is(':checked')) {
|
||||
data.eventTime = mergeDateAndTime().toDate();
|
||||
}
|
||||
|
||||
|
||||
if (!inputMatrix[data.eventType].profile) {
|
||||
delete data.profile;
|
||||
}
|
||||
@@ -258,7 +258,59 @@ function init (client, $) {
|
||||
maybePrevent(event);
|
||||
};
|
||||
|
||||
function buildConfirmText(data) {
|
||||
function validateData (data) {
|
||||
|
||||
let allOk = true;
|
||||
let messages = [];
|
||||
|
||||
console.log('Validating careportal entry: ', data.eventType);
|
||||
|
||||
if (data.eventType == 'Temporary Target') {
|
||||
if (isNaN(data.targetTop) || isNaN(data.targetBottom) || !data.targetBottom || !data.targetTop) {
|
||||
console.log('Bottom or Top target missing');
|
||||
allOk = false;
|
||||
messages.push("Please enter a valid value for both top and bottom target to save a Temporary Target");
|
||||
} else {
|
||||
|
||||
let targetTop = data.targetTop;
|
||||
let targetBottom = data.targetBottom;
|
||||
|
||||
let minTarget = 4 * 18;
|
||||
let maxTarget = 18 * 18;
|
||||
|
||||
if (units == "mmol") {
|
||||
targetTop = Math.round(targetTop / 18.0 * 10) / 10;
|
||||
targetBottom = Math.round(targetBottom / 18.0 * 10) / 10;
|
||||
minTarget = Math.round(minTarget / 18.0 * 10) / 10;
|
||||
maxTarget = Math.round(maxTarget / 18.0 * 10) / 10;
|
||||
}
|
||||
|
||||
if (targetTop > maxTarget) {
|
||||
allOk = false;
|
||||
messages.push("Temporary target high is too high");
|
||||
}
|
||||
|
||||
if (targetBottom < minTarget) {
|
||||
allOk = false;
|
||||
messages.push("Temporary target low is too low");
|
||||
}
|
||||
|
||||
if (targetTop < targetBottom || targetBottom > targetTop) {
|
||||
allOk = false;
|
||||
messages.push("The low target must be lower than the high target and high target must be higher than the low target.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
allOk
|
||||
, messages
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function buildConfirmText (data) {
|
||||
var text = [
|
||||
translate('Please verify that the data entered is correct') + ': '
|
||||
, translate('Event Type') + ': ' + translate(careportal.resolveEventName(data.eventType))
|
||||
@@ -271,22 +323,22 @@ function init (client, $) {
|
||||
}
|
||||
|
||||
if (data.duration === 0 && data.eventType === 'Temporary Target') {
|
||||
text[text.length - 1] += ' ' + translate('Cancel');
|
||||
text[text.length - 1] += ' ' + translate('Cancel');
|
||||
}
|
||||
|
||||
pushIf(data.glucose, translate('Blood Glucose') + ': ' + data.glucose);
|
||||
pushIf(data.glucose, translate('Measurement Method') + ': ' + translate(data.glucoseType));
|
||||
|
||||
pushIf(data.reason, translate('Reason') + ': ' + data.reason);
|
||||
|
||||
|
||||
var targetTop = data.targetTop;
|
||||
var targetBottom = data.targetBottom;
|
||||
|
||||
|
||||
if (units == "mmol") {
|
||||
targetTop = Math.round(data.targetTop / 18.0 * 10) / 10;
|
||||
targetBottom = Math.round(data.targetBottom / 18.0 * 10) / 10;
|
||||
}
|
||||
|
||||
targetTop = Math.round(data.targetTop / 18.0 * 10) / 10;
|
||||
targetBottom = Math.round(data.targetBottom / 18.0 * 10) / 10;
|
||||
}
|
||||
|
||||
pushIf(data.targetTop, translate('Target Top') + ': ' + targetTop);
|
||||
pushIf(data.targetBottom, translate('Target Bottom') + ': ' + targetBottom);
|
||||
|
||||
@@ -307,13 +359,27 @@ function init (client, $) {
|
||||
return text.join('\n');
|
||||
}
|
||||
|
||||
function confirmPost(data) {
|
||||
if (window.confirm(buildConfirmText(data))) {
|
||||
postTreatment(data);
|
||||
function confirmPost (data) {
|
||||
|
||||
const validation = validateData(data);
|
||||
|
||||
if (!validation.allOk) {
|
||||
|
||||
let messages = "";
|
||||
|
||||
validation.messages.forEach(function(m) {
|
||||
messages += translate(m) + "\n";
|
||||
});
|
||||
|
||||
window.alert(messages);
|
||||
} else {
|
||||
if (window.confirm(buildConfirmText(data))) {
|
||||
postTreatment(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function postTreatment(data) {
|
||||
function postTreatment (data) {
|
||||
if (data.eventType === 'Combo Bolus') {
|
||||
data.enteredinsulin = data.insulin;
|
||||
data.insulin = data.enteredinsulin * data.splitNow / 100;
|
||||
@@ -322,9 +388,9 @@ function init (client, $) {
|
||||
|
||||
$.ajax({
|
||||
method: 'POST'
|
||||
, url: '/api/v1/treatments/'
|
||||
, headers: client.headers()
|
||||
, data: data
|
||||
, url: '/api/v1/treatments/'
|
||||
, headers: client.headers()
|
||||
, data: data
|
||||
}).done(function treatmentSaved (response) {
|
||||
console.info('treatment saved', response);
|
||||
}).fail(function treatmentSaveFail (response) {
|
||||
@@ -336,7 +402,7 @@ function init (client, $) {
|
||||
|
||||
client.browserUtils.closeDrawer('#treatmentDrawer');
|
||||
}
|
||||
|
||||
|
||||
careportal.dateTimeFocus = function dateTimeFocus (event) {
|
||||
$('#othertime').prop('checked', true);
|
||||
updateTime($(this), mergeDateAndTime());
|
||||
@@ -384,4 +450,3 @@ function init (client, $) {
|
||||
}
|
||||
|
||||
module.exports = init;
|
||||
|
||||
|
||||
@@ -43,6 +43,10 @@ function init (ctx) {
|
||||
var retroFields = cleanList(settings.retroFields);
|
||||
retroFields = isEmpty(retroFields) ? ['status-symbol', 'status-label', 'iob', 'meal-assist', 'rssi'] : retroFields;
|
||||
|
||||
if (typeof settings.colorPredictionLines == 'undefined') {
|
||||
settings.colorPredictionLines = true;
|
||||
}
|
||||
|
||||
var prefs = {
|
||||
fields: fields
|
||||
, retroFields: retroFields
|
||||
@@ -59,7 +63,6 @@ function init (ctx) {
|
||||
|
||||
if (firstPrefs) {
|
||||
firstPrefs = false;
|
||||
console.info('OpenAPS Prefs:', prefs);
|
||||
}
|
||||
|
||||
return prefs;
|
||||
|
||||
Reference in New Issue
Block a user