mirror of
https://github.com/bckelley/cgm-remote-monitor.git
synced 2026-08-24 03:14:12 -05:00
* Refactor how the levels dependency is loaded, to fix some localization issues
* Moves reporting client to the bundles
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import './bundle.source';
|
||||
|
||||
window.Nightscout.report_plugins = require('../lib/report_plugins/')();
|
||||
console.info('Nightscout report bundle start');
|
||||
|
||||
window.Nightscout.report_plugins_preinit = require('../lib/report_plugins/');
|
||||
window.Nightscout.predictions = require('../lib/report/predictions');
|
||||
window.Nightscout.reportclient = require('../lib/report/reportclient');
|
||||
|
||||
console.info('Nightscout report bundle ready');
|
||||
|
||||
|
||||
@@ -88,7 +88,6 @@ function init (client, serverSettings, $) {
|
||||
//ignore these, they are always on for now
|
||||
} else {
|
||||
var id = 'plugin-' + plugin.name;
|
||||
console.log('Translated plugin is', translate(plugin.label || plugin.name));
|
||||
var dd = $('<dd><input type="checkbox" id="' + id + '" value="' + plugin.name + '"/><label for="' + id + '">' + translate(plugin.label || plugin.name) + '</label></dd>');
|
||||
showPluginsSettings.append(dd);
|
||||
dd.find('input').prop('checked', settings.showPlugins.indexOf(plugin.name) > -1);
|
||||
|
||||
+3
-1
@@ -202,6 +202,7 @@ client.load = function load (serverSettings, callback) {
|
||||
settings: client.settings
|
||||
, extendedSettings: client.settings.extendedSettings
|
||||
, language: language
|
||||
, levels: levels
|
||||
}).registerClientDefaults();
|
||||
|
||||
browserSettings.loadPluginSettings(client);
|
||||
@@ -221,7 +222,6 @@ client.load = function load (serverSettings, callback) {
|
||||
data: {}
|
||||
, bus: require('../bus')(client.settings, client.ctx)
|
||||
, settings: client.settings
|
||||
, notifications: require('../notifications')(client.settings, client.ctx)
|
||||
, pluginBase: client.plugins.base(majorPills, minorPills, statusPills, bgStatus, client.tooltip, Storages.localStorage)
|
||||
};
|
||||
|
||||
@@ -229,6 +229,8 @@ client.load = function load (serverSettings, callback) {
|
||||
levels.translate = language.translate;
|
||||
client.ctx.levels = levels;
|
||||
|
||||
client.ctx.notifications = require('../notifications')(client.settings, client.ctx);
|
||||
|
||||
client.sbx = sandbox.clientInit(client.ctx, client.now);
|
||||
client.renderer = require('./renderer')(client, d3, $);
|
||||
|
||||
|
||||
+7
-1
@@ -15,5 +15,11 @@
|
||||
"ONE_HOUR": 3600000,
|
||||
"THREE_HOURS": 10800000,
|
||||
"FOUR_HOURS": 14400000,
|
||||
"SIX_HOURS": 21600000
|
||||
"SIX_HOURS": 21600000,
|
||||
"LEVEL_URGENT": 2,
|
||||
"LEVEL_WARN": 1,
|
||||
"LEVEL_INFO": 0,
|
||||
"LEVEL_LOW": -1,
|
||||
"LEVEL_LOWEST": -2,
|
||||
"LEVEL_NONE": -3
|
||||
}
|
||||
|
||||
+8
-6
@@ -1,12 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
var constants = require('./constants');
|
||||
|
||||
var levels = {
|
||||
URGENT: 2
|
||||
, WARN: 1
|
||||
, INFO: 0
|
||||
, LOW: -1
|
||||
, LOWEST: -2
|
||||
, NONE: -3
|
||||
URGENT: constants.LEVEL_URGENT
|
||||
, WARN: constants.LEVEL_WARN
|
||||
, INFO: constants.LEVEL_INFO
|
||||
, LOW: constants.LEVEL_LOW
|
||||
, LOWEST: constants.LEVEL_LOWEST
|
||||
, NONE: constants.LEVEL_NONE
|
||||
};
|
||||
|
||||
levels.language = require('./language')();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var levels = require('./levels');
|
||||
|
||||
var THIRTY_MINUTES = 30 * 60 * 1000;
|
||||
var DEFAULT_GROUPS = ['default'];
|
||||
@@ -18,6 +17,9 @@ var Alarm = function(level, group, label) {
|
||||
var alarms = {};
|
||||
|
||||
function init (env, ctx) {
|
||||
|
||||
var levels = ctx.levels;
|
||||
|
||||
function notifications () {
|
||||
return notifications;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var levels = require('../levels');
|
||||
|
||||
function init(ctx) {
|
||||
var translate = ctx.language.translate;
|
||||
var levels = ctx.levels;
|
||||
|
||||
var bage = {
|
||||
name: 'bage'
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var levels = require('../levels');
|
||||
var times = require('../times');
|
||||
|
||||
function init (ctx) {
|
||||
|
||||
var translate = ctx.language.translate;
|
||||
var levels = ctx.levels;
|
||||
|
||||
var bwp = {
|
||||
name: 'bwp'
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var levels = require('../levels');
|
||||
|
||||
function init(ctx) {
|
||||
var translate = ctx.language.translate;
|
||||
var levels = ctx.levels;
|
||||
|
||||
var cage = {
|
||||
name: 'cage'
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
var levels = require('../levels');
|
||||
var _ = require('lodash');
|
||||
|
||||
function init (ctx) {
|
||||
var translate = ctx.language.translate;
|
||||
var levels = ctx.levels;
|
||||
|
||||
var dbsize = {
|
||||
name: 'dbsize'
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var levels = require('../levels');
|
||||
var times = require('../times');
|
||||
|
||||
function init() {
|
||||
function init(ctx) {
|
||||
|
||||
var levels = ctx.levels;
|
||||
|
||||
var errorcodes = {
|
||||
name: 'errorcodes'
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var levels = require('../levels');
|
||||
|
||||
function init(ctx) {
|
||||
var translate = ctx.language.translate;
|
||||
var levels = ctx.levels;
|
||||
|
||||
var iage = {
|
||||
name: 'iage'
|
||||
|
||||
+1
-1
@@ -3,13 +3,13 @@
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var times = require('../times');
|
||||
var levels = require('../levels');
|
||||
|
||||
// var ALL_STATUS_FIELDS = ['status-symbol', 'status-label', 'iob', 'freq', 'rssi']; Unused variable
|
||||
|
||||
function init (ctx) {
|
||||
var utils = require('../utils')(ctx);
|
||||
var translate = ctx.language.translate;
|
||||
var levels = ctx.levels;
|
||||
|
||||
var loop = {
|
||||
name: 'loop'
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var times = require('../times');
|
||||
var levels = require('../levels');
|
||||
var consts = require('../constants');
|
||||
|
||||
// var ALL_STATUS_FIELDS = ['status-symbol', 'status-label', 'iob', 'meal-assist', 'freq', 'rssi']; Unused variable
|
||||
@@ -17,6 +16,7 @@ function init (ctx) {
|
||||
};
|
||||
var translate = ctx.language.translate;
|
||||
var firstPrefs = true;
|
||||
var levels = ctx.levels;
|
||||
|
||||
openaps.getClientPrefs = function getClientPrefs() {
|
||||
return ([{
|
||||
|
||||
+1
-1
@@ -2,7 +2,6 @@
|
||||
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var levels = require('../levels');
|
||||
var times = require('../times');
|
||||
|
||||
var ALL_STATUS_FIELDS = ['reservoir', 'battery', 'clock', 'status', 'device'];
|
||||
@@ -11,6 +10,7 @@ function init (ctx) {
|
||||
var translate = ctx.language.translate;
|
||||
var timeago = require('./timeago')(ctx);
|
||||
var openaps = require('./openaps')(ctx);
|
||||
var levels = ctx.levels;
|
||||
|
||||
var pump = {
|
||||
name: 'pump'
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
var _ = require('lodash');
|
||||
var Pushover = require('pushover-notifications');
|
||||
var request = require('request');
|
||||
var levels = require('../levels');
|
||||
var times = require('../times');
|
||||
|
||||
function init (env) {
|
||||
@@ -12,6 +11,8 @@ function init (env) {
|
||||
, PRIORITY_EMERGENCY: 2
|
||||
};
|
||||
|
||||
var levels = env.levels;
|
||||
|
||||
var pushoverAPI = setupPushover(env);
|
||||
|
||||
function selectKeys (notify) {
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var times = require('../times');
|
||||
var levels = require('../levels');
|
||||
|
||||
function init(ctx) {
|
||||
var translate = ctx.language.translate;
|
||||
var levels = ctx.levels;
|
||||
|
||||
var sage = {
|
||||
name: 'sage'
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var levels = require('../levels');
|
||||
var times = require('../times');
|
||||
|
||||
function init() {
|
||||
function init(ctx) {
|
||||
|
||||
var simplealarms = {
|
||||
name: 'simplealarms'
|
||||
@@ -11,6 +10,8 @@ function init() {
|
||||
, pluginType: 'notification'
|
||||
};
|
||||
|
||||
var levels = ctx.levels;
|
||||
|
||||
simplealarms.checkNotifications = function checkNotifications(sbx) {
|
||||
|
||||
var lastSGVEntry = sbx.lastSGVEntry()
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
var levels = require('../levels');
|
||||
var times = require('../times');
|
||||
var lastChecked = new Date();
|
||||
var lastRecoveryTimeFromSuspend = new Date("1900-01-01");
|
||||
|
||||
function init(ctx) {
|
||||
var translate = ctx.language.translate;
|
||||
var levels = ctx.levels;
|
||||
|
||||
var timeago = {
|
||||
name: 'timeago',
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
const _ = require('lodash');
|
||||
const times = require('../times');
|
||||
const simplealarms = require('./simplealarms')();
|
||||
const crypto = require('crypto');
|
||||
|
||||
const MANUAL_TREATMENTS = ['BG Check', 'Meal Bolus', 'Carb Correction', 'Correction Bolus'];
|
||||
|
||||
function init() {
|
||||
function init(ctx) {
|
||||
|
||||
const treatmentnotify = {
|
||||
name: 'treatmentnotify'
|
||||
@@ -15,6 +14,8 @@ function init() {
|
||||
, pluginType: 'notification'
|
||||
};
|
||||
|
||||
const simplealarms = require('./simplealarms')(ctx);
|
||||
|
||||
//automated treatments from OpenAPS or Loop shouldn't trigger notifications or snooze alarms
|
||||
function filterTreatments (sbx) {
|
||||
var treatments = sbx.data.treatments;
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
var _ = require('lodash');
|
||||
var times = require('../times');
|
||||
var levels = require('../levels');
|
||||
|
||||
function init(ctx) {
|
||||
var translate = ctx.language.translate;
|
||||
var levels = ctx.levels;
|
||||
|
||||
var upbat = {
|
||||
name: 'upbat'
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var times = require('../times');
|
||||
var levels = require('../levels');
|
||||
|
||||
function init(ctx) {
|
||||
var levels = ctx.levels;
|
||||
var utils = require('../utils')(ctx);
|
||||
var firstPrefs = true;
|
||||
var lastStateNotification = null;
|
||||
|
||||
@@ -0,0 +1,912 @@
|
||||
// TODO:
|
||||
// - bypass nightmode in reports
|
||||
// - on save/delete treatment ctx.bus.emit('data-received'); is not enough. we must add something like 'data-updated'
|
||||
|
||||
var init = function init () {
|
||||
'use strict';
|
||||
//for the tests window isn't the global object
|
||||
var $ = window.$;
|
||||
var _ = window._;
|
||||
var moment = window.moment;
|
||||
var Nightscout = window.Nightscout;
|
||||
var client = Nightscout.client;
|
||||
var report_plugins_preinit = Nightscout.report_plugins_preinit;
|
||||
var report_plugins;
|
||||
|
||||
client.init(function loaded () {
|
||||
|
||||
report_plugins = report_plugins_preinit(client.ctx);
|
||||
Nightscout.report_plugins = report_plugins;
|
||||
|
||||
// init HTML code
|
||||
report_plugins.addHtmlFromPlugins(client);
|
||||
// make show() accessible outside for treatments.js
|
||||
report_plugins.show = show;
|
||||
|
||||
var translate = client.translate;
|
||||
|
||||
var maxInsulinValue = 0
|
||||
, maxCarbsValue = 0
|
||||
, maxDailyCarbsValue = 0;
|
||||
var maxdays = 6 * 31;
|
||||
var datastorage = {};
|
||||
var daystoshow = {};
|
||||
var sorteddaystoshow = [];
|
||||
|
||||
var targetBGdefault = {
|
||||
'mg/dl': {
|
||||
low: client.settings.thresholds.bgTargetBottom
|
||||
, high: client.settings.thresholds.bgTargetTop
|
||||
}
|
||||
, 'mmol': {
|
||||
low: client.utils.scaleMgdl(client.settings.thresholds.bgTargetBottom)
|
||||
, high: client.utils.scaleMgdl(client.settings.thresholds.bgTargetTop)
|
||||
}
|
||||
};
|
||||
|
||||
var ONE_MIN_IN_MS = 60000;
|
||||
|
||||
prepareGUI();
|
||||
|
||||
// ****** FOOD CODE START ******
|
||||
var food_categories = [];
|
||||
var food_list = [];
|
||||
|
||||
var filter = {
|
||||
category: ''
|
||||
, subcategory: ''
|
||||
, name: ''
|
||||
};
|
||||
|
||||
function fillFoodForm (event) {
|
||||
$('#rp_category').empty().append('<option value="">' + translate('(none)') + '</option>');
|
||||
Object.keys(food_categories).forEach(function eachCategory (s) {
|
||||
$('#rp_category').append('<option value="' + s + '">' + s + '</option>');
|
||||
});
|
||||
filter.category = '';
|
||||
fillFoodSubcategories();
|
||||
|
||||
$('#rp_category').change(fillFoodSubcategories);
|
||||
$('#rp_subcategory').change(doFoodFilter);
|
||||
$('#rp_name').on('input', doFoodFilter);
|
||||
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
function fillFoodSubcategories (event) {
|
||||
filter.category = $('#rp_category').val();
|
||||
filter.subcategory = '';
|
||||
$('#rp_subcategory').empty().append('<option value="">' + translate('(none)') + '</option>');
|
||||
if (filter.category !== '') {
|
||||
Object.keys(food_categories[filter.category] || {}).forEach(function eachSubCategory (s) {
|
||||
$('#rp_subcategory').append('<option value="' + s + '">' + s + '</option>');
|
||||
});
|
||||
}
|
||||
doFoodFilter();
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
function doFoodFilter (event) {
|
||||
if (event) {
|
||||
filter.category = $('#rp_category').val();
|
||||
filter.subcategory = $('#rp_subcategory').val();
|
||||
filter.name = $('#rp_name').val();
|
||||
}
|
||||
$('#rp_food').empty();
|
||||
for (var i = 0; i < food_list.length; i++) {
|
||||
if (filter.category !== '' && food_list[i].category !== filter.category) { continue; }
|
||||
if (filter.subcategory !== '' && food_list[i].subcategory !== filter.subcategory) { continue; }
|
||||
if (filter.name !== '' && food_list[i].name.toLowerCase().indexOf(filter.name.toLowerCase()) < 0) { continue; }
|
||||
var o = '';
|
||||
o += food_list[i].name + ' | ';
|
||||
o += translate('Portion') + ': ' + food_list[i].portion + ' ';
|
||||
o += food_list[i].unit + ' | ';
|
||||
o += translate('Carbs') + ': ' + food_list[i].carbs + ' g';
|
||||
$('#rp_food').append('<option value="' + food_list[i]._id + '">' + o + '</option>');
|
||||
}
|
||||
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
$('#info').html('<b>' + translate('Loading food database') + ' ...</b>');
|
||||
$.ajax('/api/v1/food/regular.json', {
|
||||
headers: client.headers()
|
||||
, success: function foodLoadSuccess (records) {
|
||||
records.forEach(function(r) {
|
||||
food_list.push(r);
|
||||
if (r.category && !food_categories[r.category]) { food_categories[r.category] = {}; }
|
||||
if (r.category && r.subcategory) { food_categories[r.category][r.subcategory] = true; }
|
||||
});
|
||||
fillFoodForm();
|
||||
}
|
||||
}).done(function() {
|
||||
if (food_list.length) {
|
||||
enableFoodGUI();
|
||||
} else {
|
||||
disableFoodGUI();
|
||||
}
|
||||
}).fail(function() {
|
||||
disableFoodGUI();
|
||||
});
|
||||
|
||||
function enableFoodGUI () {
|
||||
$('#info').html('');
|
||||
|
||||
$('.rp_foodgui').css('display', '');
|
||||
$('#rp_food').change(function(event) {
|
||||
$('#rp_enablefood').prop('checked', true);
|
||||
return maybePrevent(event);
|
||||
});
|
||||
}
|
||||
|
||||
function disableFoodGUI () {
|
||||
$('#info').html('');
|
||||
$('.rp_foodgui').css('display', 'none');
|
||||
}
|
||||
|
||||
// ****** FOOD CODE END ******
|
||||
|
||||
function prepareGUI () {
|
||||
$('.presetdates').click(function(event) {
|
||||
var days = $(this).attr('days');
|
||||
$('#rp_enabledate').prop('checked', true);
|
||||
return setDataRange(event, days);
|
||||
});
|
||||
$('#rp_show').click(show);
|
||||
$('#rp_notes').bind('input', function(event) {
|
||||
$('#rp_enablenotes').prop('checked', true);
|
||||
return maybePrevent(event);
|
||||
});
|
||||
$('#rp_eventtype').bind('input', function(event) {
|
||||
$('#rp_enableeventtype').prop('checked', true);
|
||||
return maybePrevent(event);
|
||||
});
|
||||
|
||||
// fill careportal events
|
||||
$('#rp_eventtype').empty();
|
||||
_.each(client.careportal.events, function eachEvent (event) {
|
||||
$('#rp_eventtype').append('<option value="' + event.val + '">' + translate(event.name) + '</option>');
|
||||
});
|
||||
$('#rp_eventtype').append('<option value="sensor">' + '>>> ' + translate('All sensor events') + '</option>');
|
||||
|
||||
$('#rp_targetlow').val(targetBGdefault[client.settings.units.toLowerCase()].low);
|
||||
$('#rp_targethigh').val(targetBGdefault[client.settings.units.toLowerCase()].high);
|
||||
|
||||
if (client.settings.scaleY === 'linear') {
|
||||
$('#rp_linear').prop('checked', true);
|
||||
$('#wrp_linear').prop('checked', true);
|
||||
} else {
|
||||
$('#rp_log').prop('checked', true);
|
||||
$('#wrp_log').prop('checked', true);
|
||||
}
|
||||
|
||||
$('.menutab').click(switchreport_handler);
|
||||
|
||||
setDataRange(null, 7);
|
||||
}
|
||||
|
||||
function sgvToColor (sgv, options) {
|
||||
var color = 'darkgreen';
|
||||
|
||||
if (sgv > options.targetHigh) {
|
||||
color = 'red';
|
||||
} else if (sgv < options.targetLow) {
|
||||
color = 'red';
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
function show (event) {
|
||||
var options = {
|
||||
width: 1000
|
||||
, height: 300
|
||||
, weekwidth: 1000
|
||||
, weekheight: 300
|
||||
, targetLow: 3.5
|
||||
, targetHigh: 10
|
||||
, raw: true
|
||||
, notes: true
|
||||
, food: true
|
||||
, insulin: true
|
||||
, carbs: true
|
||||
, iob: true
|
||||
, cob: true
|
||||
, basal: true
|
||||
, scale: report_plugins.consts.scaleYFromSettings(client)
|
||||
, weekscale: report_plugins.consts.scaleYFromSettings(client)
|
||||
, units: client.settings.units
|
||||
};
|
||||
|
||||
// default time range if no time range specified in GUI
|
||||
var zone = client.sbx.data.profile.getTimezone();
|
||||
var timerange = '&find[created_at][$gte]=' + moment.tz('2000-01-01', zone).toISOString();
|
||||
//console.log(timerange,zone);
|
||||
options.targetLow = parseFloat($('#rp_targetlow').val().replace(',', '.'));
|
||||
options.targetHigh = parseFloat($('#rp_targethigh').val().replace(',', '.'));
|
||||
options.raw = $('#rp_optionsraw').is(':checked');
|
||||
options.iob = $('#rp_optionsiob').is(':checked');
|
||||
options.cob = $('#rp_optionscob').is(':checked');
|
||||
options.openAps = $('#rp_optionsopenaps').is(':checked');
|
||||
options.predicted = $('#rp_optionspredicted').is(':checked');
|
||||
options.predictedTruncate = $('#rp_optionsPredictedTruncate').is(':checked');
|
||||
options.basal = $('#rp_optionsbasal').is(':checked');
|
||||
options.notes = $('#rp_optionsnotes').is(':checked');
|
||||
options.food = $('#rp_optionsfood').is(':checked');
|
||||
options.insulin = $('#rp_optionsinsulin').is(':checked');
|
||||
options.insulindistribution = $('#rp_optionsdistribution').is(':checked');
|
||||
options.carbs = $('#rp_optionscarbs').is(':checked');
|
||||
options.scale = ($('#rp_linear').is(':checked') ? report_plugins.consts.SCALE_LINEAR : report_plugins.consts.SCALE_LOG);
|
||||
options.weekscale = ($('#wrp_linear').is(':checked') ? report_plugins.consts.SCALE_LINEAR : report_plugins.consts.SCALE_LOG);
|
||||
options.order = ($('#rp_oldestontop').is(':checked') ? report_plugins.consts.ORDER_OLDESTONTOP : report_plugins.consts.ORDER_NEWESTONTOP);
|
||||
options.width = parseInt($('#rp_size :selected').attr('x'));
|
||||
options.weekwidth = parseInt($('#wrp_size :selected').attr('x'));
|
||||
options.height = parseInt($('#rp_size :selected').attr('y'));
|
||||
options.weekheight = parseInt($('#wrp_size :selected').attr('y'));
|
||||
options.loopalyzer = $("#loopalyzer").hasClass("selected"); // We only want to run through Loopalyzer if that tab is selected
|
||||
if (options.loopalyzer) {
|
||||
options.iob = true;
|
||||
options.cob = true;
|
||||
options.openAps = true;
|
||||
}
|
||||
|
||||
var matchesneeded = 0;
|
||||
|
||||
// date range
|
||||
function datefilter () {
|
||||
if ($('#rp_enabledate').is(':checked')) {
|
||||
matchesneeded++;
|
||||
var from = moment.tz($('#rp_from').val().replace(/\//g, '-') + 'T00:00:00', zone);
|
||||
var to = moment.tz($('#rp_to').val().replace(/\//g, '-') + 'T23:59:59', zone);
|
||||
timerange = '&find[created_at][$gte]=' + from.toISOString() + '&find[created_at][$lt]=' + to.toISOString();
|
||||
//console.log($('#rp_from').val(),$('#rp_to').val(),zone,timerange);
|
||||
while (from <= to) {
|
||||
if (daystoshow[from.format('YYYY-MM-DD')]) {
|
||||
daystoshow[from.format('YYYY-MM-DD')]++;
|
||||
} else {
|
||||
daystoshow[from.format('YYYY-MM-DD')] = 1;
|
||||
}
|
||||
from.add(1, 'days');
|
||||
}
|
||||
}
|
||||
//console.log('Dayfilter: ',daystoshow);
|
||||
foodfilter();
|
||||
}
|
||||
|
||||
//food filter
|
||||
function foodfilter () {
|
||||
if ($('#rp_enablefood').is(':checked')) {
|
||||
matchesneeded++;
|
||||
var _id = $('#rp_food').val();
|
||||
if (_id) {
|
||||
var treatmentData;
|
||||
var tquery = '?find[boluscalc.foods._id]=' + _id + timerange;
|
||||
$.ajax('/api/v1/treatments.json' + tquery, {
|
||||
headers: client.headers()
|
||||
, success: function(xhr) {
|
||||
treatmentData = xhr.map(function(treatment) {
|
||||
return moment.tz(treatment.created_at, zone).format('YYYY-MM-DD');
|
||||
});
|
||||
// unique it
|
||||
treatmentData = $.grep(treatmentData, function(v, k) {
|
||||
return $.inArray(v, treatmentData) === k;
|
||||
});
|
||||
treatmentData.sort(function(a, b) { return a > b; });
|
||||
}
|
||||
}).done(function() {
|
||||
//console.log('Foodfilter: ',treatmentData);
|
||||
for (var d = 0; d < treatmentData.length; d++) {
|
||||
if (daystoshow[treatmentData[d]]) {
|
||||
daystoshow[treatmentData[d]]++;
|
||||
} else {
|
||||
daystoshow[treatmentData[d]] = 1;
|
||||
}
|
||||
}
|
||||
notesfilter();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
notesfilter();
|
||||
}
|
||||
}
|
||||
|
||||
//notes filter
|
||||
function notesfilter () {
|
||||
if ($('#rp_enablenotes').is(':checked')) {
|
||||
matchesneeded++;
|
||||
var notes = $('#rp_notes').val();
|
||||
if (notes) {
|
||||
var treatmentData;
|
||||
var tquery = '?find[notes]=/' + notes + '/i';
|
||||
$.ajax('/api/v1/treatments.json' + tquery + timerange, {
|
||||
headers: client.headers()
|
||||
, success: function(xhr) {
|
||||
treatmentData = xhr.map(function(treatment) {
|
||||
return moment.tz(treatment.created_at, zone).format('YYYY-MM-DD');
|
||||
});
|
||||
// unique it
|
||||
treatmentData = $.grep(treatmentData, function(v, k) {
|
||||
return $.inArray(v, treatmentData) === k;
|
||||
});
|
||||
treatmentData.sort(function(a, b) { return a > b; });
|
||||
}
|
||||
}).done(function() {
|
||||
//console.log('Notesfilter: ',treatmentData);
|
||||
for (var d = 0; d < treatmentData.length; d++) {
|
||||
if (daystoshow[treatmentData[d]]) {
|
||||
daystoshow[treatmentData[d]]++;
|
||||
} else {
|
||||
daystoshow[treatmentData[d]] = 1;
|
||||
}
|
||||
}
|
||||
eventtypefilter();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
eventtypefilter();
|
||||
}
|
||||
}
|
||||
|
||||
//event type filter
|
||||
function eventtypefilter () {
|
||||
if ($('#rp_enableeventtype').is(':checked')) {
|
||||
matchesneeded++;
|
||||
var eventtype = $('#rp_eventtype').val();
|
||||
if (eventtype) {
|
||||
var treatmentData;
|
||||
var tquery = '?find[eventType]=/' + eventtype + '/i';
|
||||
$.ajax('/api/v1/treatments.json' + tquery + timerange, {
|
||||
headers: client.headers()
|
||||
, success: function(xhr) {
|
||||
treatmentData = xhr.map(function(treatment) {
|
||||
return moment.tz(treatment.created_at, zone).format('YYYY-MM-DD');
|
||||
});
|
||||
// unique it
|
||||
treatmentData = $.grep(treatmentData, function(v, k) {
|
||||
return $.inArray(v, treatmentData) === k;
|
||||
});
|
||||
treatmentData.sort(function(a, b) { return a > b; });
|
||||
}
|
||||
}).done(function() {
|
||||
//console.log('Eventtypefilter: ',treatmentData);
|
||||
for (var d = 0; d < treatmentData.length; d++) {
|
||||
if (daystoshow[treatmentData[d]]) {
|
||||
daystoshow[treatmentData[d]]++;
|
||||
} else {
|
||||
daystoshow[treatmentData[d]] = 1;
|
||||
}
|
||||
}
|
||||
daysfilter();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
daysfilter();
|
||||
}
|
||||
}
|
||||
|
||||
function daysfilter () {
|
||||
matchesneeded++;
|
||||
Object.keys(daystoshow).forEach(function eachDay (d) {
|
||||
var day = moment.tz(d, zone).day();
|
||||
if (day === 0 && $('#rp_su').is(':checked')) { daystoshow[d]++; }
|
||||
if (day === 1 && $('#rp_mo').is(':checked')) { daystoshow[d]++; }
|
||||
if (day === 2 && $('#rp_tu').is(':checked')) { daystoshow[d]++; }
|
||||
if (day === 3 && $('#rp_we').is(':checked')) { daystoshow[d]++; }
|
||||
if (day === 4 && $('#rp_th').is(':checked')) { daystoshow[d]++; }
|
||||
if (day === 5 && $('#rp_fr').is(':checked')) { daystoshow[d]++; }
|
||||
if (day === 6 && $('#rp_sa').is(':checked')) { daystoshow[d]++; }
|
||||
});
|
||||
countDays();
|
||||
addPreviousDayTreatments();
|
||||
display();
|
||||
}
|
||||
|
||||
function display () {
|
||||
var count = 0;
|
||||
sorteddaystoshow = [];
|
||||
$('#info').html('<b>' + translate('Loading') + ' ...</b>');
|
||||
for (var d in daystoshow) {
|
||||
if (count < maxdays) {
|
||||
$('#info').append($('<div id="info-' + d + '"></div>'));
|
||||
count++;
|
||||
loadData(d, options, dataLoadedCallback);
|
||||
} else {
|
||||
$('#info').append($('<div>' + d + ' ' + translate('not displayed') + '.</div>'));
|
||||
delete daystoshow[d];
|
||||
}
|
||||
}
|
||||
if (count === 0) {
|
||||
$('#info').html('<b>' + translate('Result is empty') + '</b>');
|
||||
$('#rp_show').css('display', '');
|
||||
}
|
||||
}
|
||||
|
||||
var dayscount = 0;
|
||||
var loadeddays = 0;
|
||||
|
||||
function countDays () {
|
||||
for (var d in daystoshow) {
|
||||
if (daystoshow.hasOwnProperty(d)) {
|
||||
if (daystoshow[d] === matchesneeded) {
|
||||
if (dayscount < maxdays) {
|
||||
dayscount++;
|
||||
}
|
||||
} else {
|
||||
delete daystoshow[d];
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log('Total: ', daystoshow, 'Matches needed: ', matchesneeded, 'Will be loaded: ', dayscount);
|
||||
}
|
||||
|
||||
function addPreviousDayTreatments () {
|
||||
for (var d in daystoshow) {
|
||||
if (daystoshow.hasOwnProperty(d)) {
|
||||
var day = moment.tz(d, zone);
|
||||
var previous = day.subtract(1, 'days');
|
||||
var formated = previous.format('YYYY-MM-DD');
|
||||
if (!daystoshow[formated]) {
|
||||
daystoshow[formated] = { treatmentsonly: true };
|
||||
console.log('Adding ' + formated + ' for loading treatments');
|
||||
dayscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log('Total: ', daystoshow, 'Matches needed: ', matchesneeded, 'Will be loaded: ', dayscount);
|
||||
}
|
||||
|
||||
function dataLoadedCallback (day) {
|
||||
loadeddays++;
|
||||
if (!daystoshow[day].treatmentsonly) {
|
||||
sorteddaystoshow.push(day);
|
||||
}
|
||||
if (loadeddays === dayscount) {
|
||||
sorteddaystoshow.sort();
|
||||
var dFrom = sorteddaystoshow[0];
|
||||
var dTo = sorteddaystoshow[(sorteddaystoshow.length - 1)];
|
||||
|
||||
if (options.order === report_plugins.consts.ORDER_NEWESTONTOP) {
|
||||
sorteddaystoshow.reverse();
|
||||
}
|
||||
loadProfileSwitch(dFrom, function loadProfileSwitchCallback () {
|
||||
loadProfilesRange(dFrom, dTo, sorteddaystoshow.length, function loadProfilesCallback () {
|
||||
$('#info > b').html('<b>' + translate('Rendering') + ' ...</b>');
|
||||
window.setTimeout(function() {
|
||||
showreports(options);
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$('#rp_show').css('display', 'none');
|
||||
daystoshow = {};
|
||||
|
||||
datefilter();
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
function showreports (options) {
|
||||
// prepare some data used in more reports
|
||||
datastorage.allstatsrecords = [];
|
||||
datastorage.alldays = 0;
|
||||
sorteddaystoshow.forEach(function eachDay (day) {
|
||||
if (!daystoshow[day].treatmentsonly) {
|
||||
datastorage.allstatsrecords = datastorage.allstatsrecords.concat(datastorage[day].statsrecords);
|
||||
datastorage.alldays++;
|
||||
}
|
||||
});
|
||||
options.maxInsulinValue = maxInsulinValue;
|
||||
options.maxCarbsValue = maxCarbsValue;
|
||||
options.maxDailyCarbsValue = maxDailyCarbsValue;
|
||||
|
||||
datastorage.treatments = [];
|
||||
datastorage.devicestatus = [];
|
||||
datastorage.combobolusTreatments = [];
|
||||
datastorage.tempbasalTreatments = [];
|
||||
Object.keys(daystoshow).forEach(function eachDay (day) {
|
||||
datastorage.treatments = datastorage.treatments.concat(datastorage[day].treatments);
|
||||
datastorage.devicestatus = datastorage.devicestatus.concat(datastorage[day].devicestatus);
|
||||
datastorage.combobolusTreatments = datastorage.combobolusTreatments.concat(datastorage[day].combobolusTreatments);
|
||||
datastorage.tempbasalTreatments = datastorage.tempbasalTreatments.concat(datastorage[day].tempbasalTreatments);
|
||||
});
|
||||
datastorage.tempbasalTreatments = Nightscout.client.ddata.processDurations(datastorage.tempbasalTreatments);
|
||||
datastorage.treatments.sort(function sort (a, b) { return a.mills - b.mills; });
|
||||
|
||||
for (var d in daystoshow) {
|
||||
if (daystoshow.hasOwnProperty(d)) {
|
||||
if (daystoshow[d].treatmentsonly) {
|
||||
delete daystoshow[d];
|
||||
delete datastorage[d];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
report_plugins.eachPlugin(function(plugin) {
|
||||
// jquery plot doesn't draw to hidden div
|
||||
$('#' + plugin.name + '-placeholder').css('display', '');
|
||||
|
||||
console.log('Drawing ', plugin.name);
|
||||
|
||||
var skipRender = false;
|
||||
|
||||
if (plugin.name == 'daytoday' && !$('#daytoday').hasClass('selected')) skipRender = true;
|
||||
if (plugin.name == 'treatments' && !$('#treatments').hasClass('selected')) skipRender = true;
|
||||
if (plugin.name == 'weektoweek' && !$('#weektoweek').hasClass('selected')) skipRender = true;
|
||||
if (plugin.name == 'loopalyzer' && !$('#loopalyzer').hasClass('selected')) skipRender = true;
|
||||
|
||||
if (skipRender) {
|
||||
console.log('Skipping ', plugin.name);
|
||||
} else {
|
||||
plugin.report(datastorage, sorteddaystoshow, options);
|
||||
}
|
||||
|
||||
if (!$('#' + plugin.name).hasClass('selected')) {
|
||||
$('#' + plugin.name + '-placeholder').css('display', 'none');
|
||||
}
|
||||
});
|
||||
|
||||
$('#info').html('');
|
||||
$('#rp_show').css('display', '');
|
||||
}
|
||||
|
||||
function setDataRange (event, days) {
|
||||
$('#rp_to').val(moment().format('YYYY-MM-DD'));
|
||||
$('#rp_from').val(moment().add(-days + 1, 'days').format('YYYY-MM-DD'));
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
function switchreport_handler (event) {
|
||||
var id = $(this).attr('id');
|
||||
|
||||
$('.menutab').removeClass('selected');
|
||||
$('#' + id).addClass('selected');
|
||||
|
||||
$('.tabplaceholder').css('display', 'none');
|
||||
$('#' + id + '-placeholder').css('display', '');
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
function loadData (day, options, callback) {
|
||||
// check for loaded data
|
||||
if ((options.openAps || options.predicted || options.iob || options.cob) && datastorage[day] && !datastorage[day].devicestatus.length) {
|
||||
// OpenAPS requested but data not loaded. Load anyway ...
|
||||
} else if (datastorage[day] && day !== moment().format('YYYY-MM-DD')) {
|
||||
callback(day);
|
||||
return;
|
||||
}
|
||||
// patientData = [actual, predicted, mbg, treatment, cal, devicestatusData];
|
||||
var data = {};
|
||||
var cgmData = []
|
||||
, mbgData = []
|
||||
, treatmentData = []
|
||||
, calData = [];
|
||||
var from;
|
||||
if (client.sbx.data.profile.getTimezone()) {
|
||||
from = moment(day).tz(client.sbx.data.profile.getTimezone()).startOf('day').format('x');
|
||||
} else {
|
||||
from = moment(day).startOf('day').format('x');
|
||||
}
|
||||
from = parseInt(from);
|
||||
var to = from + 1000 * 60 * 60 * 24;
|
||||
|
||||
function loadCGMData () {
|
||||
if (daystoshow[day].treatmentsonly) {
|
||||
data.sgv = [];
|
||||
data.mbg = [];
|
||||
data.cal = [];
|
||||
return $.Deferred().resolve();
|
||||
}
|
||||
$('#info-' + day).html('<b>' + translate('Loading CGM data of') + ' ' + day + ' ...</b>');
|
||||
var query = '?find[date][$gte]=' + from + '&find[date][$lt]=' + to + '&count=10000';
|
||||
return $.ajax('/api/v1/entries.json' + query, {
|
||||
headers: client.headers()
|
||||
, success: function(xhr) {
|
||||
xhr.forEach(function(element) {
|
||||
if (element) {
|
||||
if (element.mbg) {
|
||||
mbgData.push({
|
||||
y: element.mbg
|
||||
, mills: element.date
|
||||
, d: element.dateString
|
||||
, device: element.device
|
||||
});
|
||||
} else if (element.sgv) {
|
||||
cgmData.push({
|
||||
y: element.sgv
|
||||
, mills: element.date
|
||||
, d: element.dateString
|
||||
, device: element.device
|
||||
, filtered: element.filtered
|
||||
, unfiltered: element.unfiltered
|
||||
, noise: element.noise
|
||||
, rssi: element.rssi
|
||||
, sgv: element.sgv
|
||||
});
|
||||
} else if (element.type === 'cal') {
|
||||
calData.push({
|
||||
mills: element.date + 1
|
||||
, d: element.dateString
|
||||
, scale: element.scale
|
||||
, intercept: element.intercept
|
||||
, slope: element.slope
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// sometimes cgm contains duplicates. uniq it.
|
||||
data.sgv = cgmData.slice();
|
||||
data.sgv.sort(function(a, b) { return a.mills - b.mills; });
|
||||
var lastDate = 0;
|
||||
data.sgv = data.sgv.filter(function(d) {
|
||||
var ok = (lastDate + ONE_MIN_IN_MS) <= d.mills;
|
||||
lastDate = d.mills;
|
||||
if (!ok) { console.log("itm", JSON.stringify(d)); }
|
||||
return ok;
|
||||
});
|
||||
data.mbg = mbgData.slice();
|
||||
data.mbg.sort(function(a, b) { return a.mills - b.mills; });
|
||||
data.cal = calData.slice();
|
||||
data.cal.sort(function(a, b) { return a.mills - b.mills; });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadTreatmentData () {
|
||||
if (!datastorage.profileSwitchTreatments)
|
||||
datastorage.profileSwitchTreatments = [];
|
||||
$('#info-' + day).html('<b>' + translate('Loading treatments data of') + ' ' + day + ' ...</b>');
|
||||
var tquery = '?find[created_at][$gte]=' + new Date(from).toISOString() + '&find[created_at][$lt]=' + new Date(to).toISOString() + '&count=1000';
|
||||
return $.ajax('/api/v1/treatments.json' + tquery, {
|
||||
headers: client.headers()
|
||||
, cache: false
|
||||
, success: function(xhr) {
|
||||
treatmentData = xhr.map(function(treatment) {
|
||||
var timestamp = new Date(treatment.timestamp || treatment.created_at);
|
||||
treatment.mills = timestamp.getTime();
|
||||
return treatment;
|
||||
});
|
||||
data.treatments = treatmentData.slice();
|
||||
data.treatments.sort(function(a, b) { return a.mills - b.mills; });
|
||||
// filter 'Combo Bolus' events
|
||||
data.combobolusTreatments = data.treatments.filter(function filterComboBoluses (t) {
|
||||
return t.eventType === 'Combo Bolus';
|
||||
});
|
||||
// filter temp basal treatments
|
||||
data.tempbasalTreatments = data.treatments.filter(function filterTempBasals (t) {
|
||||
return t.eventType === 'Temp Basal';
|
||||
});
|
||||
// filter profile switch treatments
|
||||
var profileSwitch = data.treatments.filter(function filterProfileSwitch (t) {
|
||||
return t.eventType === 'Profile Switch';
|
||||
});
|
||||
datastorage.profileSwitchTreatments = datastorage.profileSwitchTreatments.concat(profileSwitch);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadDevicestatusData () {
|
||||
if (daystoshow[day].treatmentsonly) {
|
||||
data.devicestatus = [];
|
||||
return $.Deferred().resolve();
|
||||
}
|
||||
if (options.iob || options.cob || options.openAps || options.predicted) {
|
||||
$('#info-' + day).html('<b>' + translate('Loading device status data of') + ' ' + day + ' ...</b>');
|
||||
var tquery = '?find[created_at][$gte]=' + new Date(from).toISOString() + '&find[created_at][$lt]=' + new Date(to).toISOString() + '&count=10000';
|
||||
return $.ajax('/api/v1/devicestatus.json' + tquery, {
|
||||
headers: client.headers()
|
||||
, success: function(xhr) {
|
||||
data.devicestatus = xhr.map(function(devicestatus) {
|
||||
devicestatus.mills = new Date(devicestatus.timestamp || devicestatus.created_at).getTime();
|
||||
return devicestatus;
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
data.devicestatus = [];
|
||||
return $.Deferred().resolve();
|
||||
}
|
||||
}
|
||||
|
||||
$.when(loadCGMData(), loadTreatmentData(), loadDevicestatusData()).done(function() {
|
||||
$('#info-' + day).html('<b>' + translate('Processing data of') + ' ' + day + ' ...</b>');
|
||||
processData(data, day, options, callback);
|
||||
});
|
||||
}
|
||||
|
||||
function loadProfileSwitch (from, callback) {
|
||||
$('#info > b').html('<b>' + translate('Loading profile switch data') + ' ...</b>');
|
||||
var tquery = '?find[eventType]=Profile Switch' + '&find[created_at][$lte]=' + new Date(from).toISOString() + '&count=1';
|
||||
$.ajax('/api/v1/treatments.json' + tquery, {
|
||||
headers: client.headers()
|
||||
, success: function(xhr) {
|
||||
var treatmentData = xhr.map(function(treatment) {
|
||||
var timestamp = new Date(treatment.timestamp || treatment.created_at);
|
||||
treatment.mills = timestamp.getTime();
|
||||
return treatment;
|
||||
});
|
||||
if (!datastorage.profileSwitchTreatments)
|
||||
datastorage.profileSwitchTreatments = [];
|
||||
datastorage.profileSwitchTreatments = datastorage.profileSwitchTreatments.concat(treatmentData);
|
||||
datastorage.profileSwitchTreatments.sort(function(a, b) { return a.mills - b.mills; });
|
||||
}
|
||||
}).done(function() {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function loadProfilesRange (dateFrom, dateTo, dayCount, callback) {
|
||||
$('#info > b').html('<b>' + translate('Loading profile range') + ' ...</b>');
|
||||
|
||||
$.when(
|
||||
loadProfilesRangeCore(dateFrom, dateTo, dayCount)
|
||||
, loadProfilesRangePrevious(dateFrom)
|
||||
, loadProfilesRangeNext(dateTo)
|
||||
)
|
||||
.done(callback)
|
||||
.fail(function() {
|
||||
datastorage.profiles = [];
|
||||
});
|
||||
}
|
||||
|
||||
function loadProfilesRangeCore (dateFrom, dateTo, dayCount) {
|
||||
$('#info > b').html('<b>' + translate('Loading core profiles') + ' ...</b>');
|
||||
|
||||
//The results must be returned in descending order to work with key logic in routines such as getCurrentProfile
|
||||
var tquery = '?find[startDate][$gte]=' + new Date(dateFrom).toISOString() + '&find[startDate][$lte]=' + new Date(dateTo).toISOString() + '&sort[startDate]=-1&count=1000';
|
||||
|
||||
return $.ajax('/api/v1/profiles' + tquery, {
|
||||
headers: client.headers()
|
||||
, async: false
|
||||
, success: function(records) {
|
||||
datastorage.profiles = records;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadProfilesRangePrevious (dateFrom) {
|
||||
$('#info > b').html('<b>' + translate('Loading previous profile') + ' ...</b>');
|
||||
|
||||
//Find first one before the start date and add to datastorage.profiles
|
||||
var tquery = '?find[startDate][$lt]=' + new Date(dateFrom).toISOString() + '&sort[startDate]=-1&count=1';
|
||||
|
||||
return $.ajax('/api/v1/profiles' + tquery, {
|
||||
headers: client.headers()
|
||||
, async: false
|
||||
, success: function(records) {
|
||||
records.forEach(function(r) {
|
||||
datastorage.profiles.push(r);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadProfilesRangeNext (dateTo) {
|
||||
$('#info > b').html('<b>' + translate('Loading next profile') + ' ...</b>');
|
||||
|
||||
//Find first one after the end date and add to datastorage.profiles
|
||||
var tquery = '?find[startDate][$gt]=' + new Date(dateTo).toISOString() + '&sort[startDate]=1&count=1';
|
||||
|
||||
return $.ajax('/api/v1/profiles' + tquery, {
|
||||
headers: client.headers()
|
||||
, async: false
|
||||
, success: function(records) {
|
||||
records.forEach(function(r) {
|
||||
//must be inserted as top to maintain profiles being sorted by date in descending order
|
||||
datastorage.profiles.unshift(r);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function processData (data, day, options, callback) {
|
||||
if (daystoshow[day].treatmentsonly) {
|
||||
datastorage[day] = data;
|
||||
$('#info-' + day).html('');
|
||||
callback(day);
|
||||
return;
|
||||
}
|
||||
// treatments
|
||||
data.dailyCarbs = 0;
|
||||
data.dailyProtein = 0;
|
||||
data.dailyFat = 0;
|
||||
|
||||
data.treatments.forEach(function(d) {
|
||||
if (parseFloat(d.insulin) > maxInsulinValue) {
|
||||
maxInsulinValue = parseFloat(d.insulin);
|
||||
}
|
||||
if (parseFloat(d.carbs) > maxCarbsValue) {
|
||||
maxCarbsValue = parseFloat(d.carbs);
|
||||
}
|
||||
if (d.carbs) {
|
||||
data.dailyCarbs += Number(d.carbs);
|
||||
}
|
||||
if (d.protein) {
|
||||
data.dailyProtein += Number(d.protein);
|
||||
}
|
||||
if (d.fat) {
|
||||
data.dailyFat += Number(d.fat);
|
||||
}
|
||||
});
|
||||
if (data.dailyCarbs > maxDailyCarbsValue) {
|
||||
maxDailyCarbsValue = data.dailyCarbs;
|
||||
}
|
||||
|
||||
var cal = data.cal[data.cal.length - 1];
|
||||
var temp1 = [];
|
||||
var rawbg = client.rawbg;
|
||||
if (cal) {
|
||||
temp1 = data.sgv.map(function(entry) {
|
||||
entry.mgdl = entry.y; // value names changed from enchilada
|
||||
var rawBg = rawbg.calc(entry, cal);
|
||||
return { mills: entry.mills, date: new Date(entry.mills - 2 * 1000), y: rawBg, sgv: client.utils.scaleMgdl(rawBg), color: 'gray', type: 'rawbg', filtered: entry.filtered, unfiltered: entry.unfiltered };
|
||||
}).filter(function(entry) { return entry.y > 0 });
|
||||
}
|
||||
var temp2 = data.sgv.map(function(obj) {
|
||||
return { mills: obj.mills, date: new Date(obj.mills), y: obj.y, sgv: client.utils.scaleMgdl(obj.y), color: sgvToColor(client.utils.scaleMgdl(obj.y), options), type: 'sgv', noise: obj.noise, filtered: obj.filtered, unfiltered: obj.unfiltered };
|
||||
});
|
||||
data.sgv = [].concat(temp1, temp2);
|
||||
|
||||
//Add MBG's also, pretend they are SGV's
|
||||
data.sgv = data.sgv.concat(data.mbg.map(function(obj) { return { date: new Date(obj.mills), y: obj.y, sgv: client.utils.scaleMgdl(obj.y), color: 'red', type: 'mbg', device: obj.device } }));
|
||||
|
||||
// make sure data range will be exactly 24h
|
||||
var from;
|
||||
if (client.sbx.data.profile.getTimezone()) {
|
||||
from = moment(day).tz(client.sbx.data.profile.getTimezone()).startOf('day').toDate();
|
||||
} else {
|
||||
from = moment(day).startOf('day').toDate();
|
||||
}
|
||||
var to = new Date(from.getTime() + 1000 * 60 * 60 * 24);
|
||||
data.sgv.push({ date: from, y: 40, sgv: 40, color: 'transparent', type: 'rawbg' });
|
||||
data.sgv.push({ date: to, y: 40, sgv: 40, color: 'transparent', type: 'rawbg' });
|
||||
|
||||
// clear error data. we don't need it to display them
|
||||
data.sgv = data.sgv.filter(function(d) {
|
||||
if (d.y < 39) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
data.sgv = data.sgv.map(function eachSgv (sgv) {
|
||||
var status = _.find(data.devicestatus, function(d) {
|
||||
return d.mills >= sgv.mills && d.mills < sgv.mills + 5 * 60 * 1000;
|
||||
});
|
||||
|
||||
if (status && status.openaps) {
|
||||
sgv.openaps = status.openaps;
|
||||
}
|
||||
return sgv;
|
||||
});
|
||||
|
||||
// for other reports
|
||||
data.statsrecords = data.sgv.filter(function(r) {
|
||||
if (r.type) {
|
||||
return r.type === 'sgv';
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}).map(function(r) {
|
||||
var ret = {};
|
||||
ret.sgv = parseFloat(r.sgv);
|
||||
ret.bgValue = parseInt(r.y);
|
||||
ret.displayTime = r.date;
|
||||
return ret;
|
||||
});
|
||||
|
||||
datastorage[day] = data;
|
||||
$('#info-' + day).html('');
|
||||
callback(day);
|
||||
}
|
||||
|
||||
function maybePrevent (event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = init;
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
function init() {
|
||||
function init(ctx) {
|
||||
var consts = {
|
||||
SCALE_LINEAR: 0
|
||||
, SCALE_LOG: 1
|
||||
@@ -44,7 +44,7 @@ function init() {
|
||||
plugins.utils = require('./utils')({
|
||||
//TODO: refactor so all this happens after init somehow
|
||||
// until then use some defaults so things don't blow up
|
||||
language: require('../language')()
|
||||
language: ctx.language
|
||||
, settings: {}
|
||||
});
|
||||
|
||||
|
||||
@@ -199,6 +199,7 @@ function boot (env, language) {
|
||||
ctx.plugins = require('../plugins')({
|
||||
settings: env.settings
|
||||
, language: ctx.language
|
||||
, levels: ctx.levels
|
||||
}).registerServerDefaults();
|
||||
|
||||
ctx.pushover = require('../plugins/pushover')(env);
|
||||
|
||||
@@ -4,7 +4,6 @@ const _ = require('lodash');
|
||||
const crypto = require('crypto');
|
||||
const NodeCache = require('node-cache');
|
||||
|
||||
const levels = require('../levels');
|
||||
const times = require('../times');
|
||||
|
||||
function init (env, ctx) {
|
||||
@@ -12,7 +11,7 @@ function init (env, ctx) {
|
||||
function pushnotify () {
|
||||
return pushnotify;
|
||||
}
|
||||
|
||||
var levels = ctx.levels;
|
||||
var receipts = new NodeCache({ stdTTL: times.hour().secs, checkperiod: times.mins(5).secs });
|
||||
var recentlySent = new NodeCache({ stdTTL: times.mins(15).secs, checkperiod: 20 });
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var levels = require('../levels');
|
||||
var times = require('../times');
|
||||
var calcData = require('../data/calcdelta');
|
||||
var ObjectID = require('mongodb').ObjectID;
|
||||
@@ -11,6 +10,8 @@ function init (env, ctx, server) {
|
||||
return websocket;
|
||||
}
|
||||
|
||||
var levels = ctx.levels;
|
||||
|
||||
//var log_yellow = '\x1B[33m';
|
||||
var log_green = '\x1B[32m';
|
||||
var log_magenta = '\x1B[35m';
|
||||
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var levels = require('./levels');
|
||||
var constants = require('./constants.json');
|
||||
|
||||
function init () {
|
||||
@@ -341,7 +340,7 @@ function init () {
|
||||
}
|
||||
|
||||
function isUrgentHighAlarmEnabled(notify) {
|
||||
return notify.eventName === 'high' && notify.level === levels.URGENT && settings.alarmUrgentHigh;
|
||||
return notify.eventName === 'high' && notify.level === constants.LEVEL_URGENT && settings.alarmUrgentHigh;
|
||||
}
|
||||
|
||||
function isHighAlarmEnabled(notify) {
|
||||
@@ -349,7 +348,7 @@ function init () {
|
||||
}
|
||||
|
||||
function isUrgentLowAlarmEnabled(notify) {
|
||||
return notify.eventName === 'low' && notify.level === levels.URGENT && settings.alarmUrgentLow;
|
||||
return notify.eventName === 'low' && notify.level === constants.LEVEL_URGENT && settings.alarmUrgentLow;
|
||||
}
|
||||
|
||||
function isLowAlarmEnabled(notify) {
|
||||
@@ -375,7 +374,7 @@ function init () {
|
||||
snoozeTime = settings.alarmUrgentLowMins;
|
||||
} else if (isLowAlarmEnabled(notify)) {
|
||||
snoozeTime = settings.alarmLowMins;
|
||||
} else if (notify.level === levels.URGENT) {
|
||||
} else if (notify.level === constants.LEVEL_URGENT) {
|
||||
snoozeTime = settings.alarmUrgentMins;
|
||||
} else {
|
||||
snoozeTime = settings.alarmWarnMins;
|
||||
|
||||
+3
-919
@@ -1,922 +1,6 @@
|
||||
// TODO:
|
||||
// - bypass nightmode in reports
|
||||
// - on save/delete treatment ctx.bus.emit('data-received'); is not enough. we must add something like 'data-updated'
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
//for the tests window isn't the global object
|
||||
var $ = window.$;
|
||||
var _ = window._;
|
||||
var moment = window.moment;
|
||||
var Nightscout = window.Nightscout;
|
||||
var client = Nightscout.client;
|
||||
var report_plugins = Nightscout.report_plugins;
|
||||
|
||||
client.init(function loaded () {
|
||||
|
||||
// init HTML code
|
||||
report_plugins.addHtmlFromPlugins( client );
|
||||
// make show() accessible outside for treatments.js
|
||||
report_plugins.show = show;
|
||||
|
||||
var translate = client.translate;
|
||||
|
||||
var maxInsulinValue = 0
|
||||
,maxCarbsValue = 0
|
||||
,maxDailyCarbsValue = 0;
|
||||
var maxdays = 6 * 31;
|
||||
var datastorage = {};
|
||||
var daystoshow = {};
|
||||
var sorteddaystoshow = [];
|
||||
|
||||
var targetBGdefault = {
|
||||
'mg/dl': {
|
||||
low: client.settings.thresholds.bgTargetBottom
|
||||
, high: client.settings.thresholds.bgTargetTop
|
||||
}
|
||||
, 'mmol': {
|
||||
low: client.utils.scaleMgdl(client.settings.thresholds.bgTargetBottom)
|
||||
, high: client.utils.scaleMgdl(client.settings.thresholds.bgTargetTop)
|
||||
}
|
||||
};
|
||||
|
||||
var ONE_MIN_IN_MS = 60000;
|
||||
|
||||
prepareGUI();
|
||||
|
||||
// ****** FOOD CODE START ******
|
||||
var food_categories = [];
|
||||
var food_list = [];
|
||||
|
||||
var filter = {
|
||||
category: ''
|
||||
, subcategory: ''
|
||||
, name: ''
|
||||
};
|
||||
|
||||
function fillFoodForm(event) {
|
||||
$('#rp_category').empty().append('<option value="">' + translate('(none)') + '</option>');
|
||||
Object.keys(food_categories).forEach(function eachCategory(s) {
|
||||
$('#rp_category').append('<option value="' + s + '">' + s + '</option>');
|
||||
$(document).ready(function() {
|
||||
console.log('Application got ready event');
|
||||
window.Nightscout.reportclient();
|
||||
});
|
||||
filter.category = '';
|
||||
fillFoodSubcategories();
|
||||
|
||||
$('#rp_category').change(fillFoodSubcategories);
|
||||
$('#rp_subcategory').change(doFoodFilter);
|
||||
$('#rp_name').on('input',doFoodFilter);
|
||||
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
function fillFoodSubcategories(event) {
|
||||
filter.category = $('#rp_category').val();
|
||||
filter.subcategory = '';
|
||||
$('#rp_subcategory').empty().append('<option value="">' + translate('(none)') + '</option>');
|
||||
if (filter.category !== '') {
|
||||
Object.keys(food_categories[filter.category] || {}).forEach(function eachSubCategory(s) {
|
||||
$('#rp_subcategory').append('<option value="' + s + '">' + s + '</option>');
|
||||
});
|
||||
}
|
||||
doFoodFilter();
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
function doFoodFilter(event) {
|
||||
if (event) {
|
||||
filter.category = $('#rp_category').val();
|
||||
filter.subcategory = $('#rp_subcategory').val();
|
||||
filter.name = $('#rp_name').val();
|
||||
}
|
||||
$('#rp_food').empty();
|
||||
for (var i=0; i<food_list.length; i++) {
|
||||
if (filter.category !== '' && food_list[i].category !== filter.category) { continue; }
|
||||
if (filter.subcategory !== '' && food_list[i].subcategory !== filter.subcategory) { continue; }
|
||||
if (filter.name !== '' && food_list[i].name.toLowerCase().indexOf(filter.name.toLowerCase()) < 0) { continue; }
|
||||
var o = '';
|
||||
o += food_list[i].name + ' | ';
|
||||
o += translate('Portion')+': ' + food_list[i].portion + ' ';
|
||||
o += food_list[i].unit + ' | ';
|
||||
o += translate('Carbs')+': ' + food_list[i].carbs+' g';
|
||||
$('#rp_food').append('<option value="' + food_list[i]._id + '">' + o + '</option>');
|
||||
}
|
||||
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
$('#info').html('<b>'+translate('Loading food database')+' ...</b>');
|
||||
$.ajax('/api/v1/food/regular.json', {
|
||||
headers: client.headers()
|
||||
, success: function foodLoadSuccess(records) {
|
||||
records.forEach(function (r) {
|
||||
food_list.push(r);
|
||||
if (r.category && !food_categories[r.category]) { food_categories[r.category] = {}; }
|
||||
if (r.category && r.subcategory) { food_categories[r.category][r.subcategory] = true; }
|
||||
});
|
||||
fillFoodForm();
|
||||
}
|
||||
}).done(function() {
|
||||
if (food_list.length) {
|
||||
enableFoodGUI();
|
||||
} else {
|
||||
disableFoodGUI();
|
||||
}
|
||||
}).fail(function() {
|
||||
disableFoodGUI();
|
||||
});
|
||||
|
||||
function enableFoodGUI( ) {
|
||||
$('#info').html('');
|
||||
|
||||
$('.rp_foodgui').css('display','');
|
||||
$('#rp_food').change(function (event) {
|
||||
$('#rp_enablefood').prop('checked',true);
|
||||
return maybePrevent(event);
|
||||
});
|
||||
}
|
||||
|
||||
function disableFoodGUI(){
|
||||
$('#info').html('');
|
||||
$('.rp_foodgui').css('display','none');
|
||||
}
|
||||
|
||||
// ****** FOOD CODE END ******
|
||||
|
||||
function prepareGUI() {
|
||||
$('.presetdates').click(function(event) {
|
||||
var days = $(this).attr('days');
|
||||
$('#rp_enabledate').prop('checked',true);
|
||||
return setDataRange(event,days);
|
||||
});
|
||||
$('#rp_show').click(show);
|
||||
$('#rp_notes').bind('input', function (event) {
|
||||
$('#rp_enablenotes').prop('checked',true);
|
||||
return maybePrevent(event);
|
||||
});
|
||||
$('#rp_eventtype').bind('input', function (event) {
|
||||
$('#rp_enableeventtype').prop('checked',true);
|
||||
return maybePrevent(event);
|
||||
});
|
||||
|
||||
// fill careportal events
|
||||
$('#rp_eventtype').empty();
|
||||
_.each(client.careportal.events, function eachEvent(event) {
|
||||
$('#rp_eventtype').append('<option value="' + event.val+ '">' + translate(event.name) + '</option>');
|
||||
});
|
||||
$('#rp_eventtype').append('<option value="sensor">' + '>>> ' + translate('All sensor events') + '</option>');
|
||||
|
||||
$('#rp_targetlow').val(targetBGdefault[client.settings.units.toLowerCase()].low);
|
||||
$('#rp_targethigh').val(targetBGdefault[client.settings.units.toLowerCase()].high);
|
||||
|
||||
if (client.settings.scaleY === 'linear') {
|
||||
$('#rp_linear').prop('checked', true);
|
||||
$('#wrp_linear').prop('checked', true);
|
||||
} else {
|
||||
$('#rp_log').prop('checked', true);
|
||||
$('#wrp_log').prop('checked', true);
|
||||
}
|
||||
|
||||
$('.menutab').click(switchreport_handler);
|
||||
|
||||
setDataRange(null,7);
|
||||
}
|
||||
|
||||
function sgvToColor(sgv,options) {
|
||||
var color = 'darkgreen';
|
||||
|
||||
if (sgv > options.targetHigh) {
|
||||
color = 'red';
|
||||
} else if (sgv < options.targetLow) {
|
||||
color = 'red';
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
function show(event) {
|
||||
var options = {
|
||||
width: 1000
|
||||
, height: 300
|
||||
, weekwidth: 1000
|
||||
, weekheight: 300
|
||||
, targetLow: 3.5
|
||||
, targetHigh: 10
|
||||
, raw: true
|
||||
, notes: true
|
||||
, food: true
|
||||
, insulin: true
|
||||
, carbs: true
|
||||
, iob : true
|
||||
, cob : true
|
||||
, basal : true
|
||||
, scale: report_plugins.consts.scaleYFromSettings(client)
|
||||
, weekscale: report_plugins.consts.scaleYFromSettings(client)
|
||||
, units: client.settings.units
|
||||
};
|
||||
|
||||
// default time range if no time range specified in GUI
|
||||
var zone = client.sbx.data.profile.getTimezone();
|
||||
var timerange = '&find[created_at][$gte]='+moment.tz('2000-01-01',zone).toISOString();
|
||||
//console.log(timerange,zone);
|
||||
options.targetLow = parseFloat($('#rp_targetlow').val().replace(',','.'));
|
||||
options.targetHigh = parseFloat($('#rp_targethigh').val().replace(',','.'));
|
||||
options.raw = $('#rp_optionsraw').is(':checked');
|
||||
options.iob = $('#rp_optionsiob').is(':checked');
|
||||
options.cob = $('#rp_optionscob').is(':checked');
|
||||
options.openAps = $('#rp_optionsopenaps').is(':checked');
|
||||
options.predicted = $('#rp_optionspredicted').is(':checked');
|
||||
options.predictedTruncate = $('#rp_optionsPredictedTruncate').is(':checked');
|
||||
options.basal = $('#rp_optionsbasal').is(':checked');
|
||||
options.notes = $('#rp_optionsnotes').is(':checked');
|
||||
options.food = $('#rp_optionsfood').is(':checked');
|
||||
options.insulin = $('#rp_optionsinsulin').is(':checked');
|
||||
options.insulindistribution = $('#rp_optionsdistribution').is(':checked');
|
||||
options.carbs = $('#rp_optionscarbs').is(':checked');
|
||||
options.scale = ( $('#rp_linear').is(':checked') ? report_plugins.consts.SCALE_LINEAR : report_plugins.consts.SCALE_LOG );
|
||||
options.weekscale = ( $('#wrp_linear').is(':checked') ? report_plugins.consts.SCALE_LINEAR : report_plugins.consts.SCALE_LOG );
|
||||
options.order = ( $('#rp_oldestontop').is(':checked') ? report_plugins.consts.ORDER_OLDESTONTOP : report_plugins.consts.ORDER_NEWESTONTOP );
|
||||
options.width = parseInt($('#rp_size :selected').attr('x'));
|
||||
options.weekwidth = parseInt($('#wrp_size :selected').attr('x'));
|
||||
options.height = parseInt($('#rp_size :selected').attr('y'));
|
||||
options.weekheight = parseInt($('#wrp_size :selected').attr('y'));
|
||||
options.loopalyzer = $("#loopalyzer").hasClass( "selected" ); // We only want to run through Loopalyzer if that tab is selected
|
||||
if (options.loopalyzer) {
|
||||
options.iob = true;
|
||||
options.cob = true;
|
||||
options.openAps = true;
|
||||
}
|
||||
|
||||
var matchesneeded = 0;
|
||||
|
||||
// date range
|
||||
function datefilter() {
|
||||
if ($('#rp_enabledate').is(':checked')) {
|
||||
matchesneeded++;
|
||||
var from = moment.tz($('#rp_from').val().replace(/\//g,'-') + 'T00:00:00',zone);
|
||||
var to = moment.tz($('#rp_to').val().replace(/\//g,'-') + 'T23:59:59',zone);
|
||||
timerange = '&find[created_at][$gte]='+from.toISOString()+'&find[created_at][$lt]='+to.toISOString();
|
||||
//console.log($('#rp_from').val(),$('#rp_to').val(),zone,timerange);
|
||||
while (from <= to) {
|
||||
if (daystoshow[from.format('YYYY-MM-DD')]) {
|
||||
daystoshow[from.format('YYYY-MM-DD')]++;
|
||||
} else {
|
||||
daystoshow[from.format('YYYY-MM-DD')] = 1;
|
||||
}
|
||||
from.add(1, 'days');
|
||||
}
|
||||
}
|
||||
//console.log('Dayfilter: ',daystoshow);
|
||||
foodfilter();
|
||||
}
|
||||
|
||||
//food filter
|
||||
function foodfilter() {
|
||||
if ($('#rp_enablefood').is(':checked')) {
|
||||
matchesneeded++;
|
||||
var _id = $('#rp_food').val();
|
||||
if (_id) {
|
||||
var treatmentData;
|
||||
var tquery = '?find[boluscalc.foods._id]=' + _id + timerange;
|
||||
$.ajax('/api/v1/treatments.json'+tquery, {
|
||||
headers: client.headers()
|
||||
, success: function (xhr) {
|
||||
treatmentData = xhr.map(function (treatment) {
|
||||
return moment.tz(treatment.created_at,zone).format('YYYY-MM-DD');
|
||||
});
|
||||
// unique it
|
||||
treatmentData = $.grep(treatmentData, function(v, k){
|
||||
return $.inArray(v ,treatmentData) === k;
|
||||
});
|
||||
treatmentData.sort(function(a, b) { return a > b; });
|
||||
}
|
||||
}).done(function () {
|
||||
//console.log('Foodfilter: ',treatmentData);
|
||||
for (var d=0; d<treatmentData.length; d++) {
|
||||
if (daystoshow[treatmentData[d]]) {
|
||||
daystoshow[treatmentData[d]]++;
|
||||
} else {
|
||||
daystoshow[treatmentData[d]] = 1;
|
||||
}
|
||||
}
|
||||
notesfilter();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
notesfilter();
|
||||
}
|
||||
}
|
||||
|
||||
//notes filter
|
||||
function notesfilter() {
|
||||
if ($('#rp_enablenotes').is(':checked')) {
|
||||
matchesneeded++;
|
||||
var notes = $('#rp_notes').val();
|
||||
if (notes) {
|
||||
var treatmentData;
|
||||
var tquery = '?find[notes]=/' + notes + '/i';
|
||||
$.ajax('/api/v1/treatments.json' + tquery + timerange, {
|
||||
headers: client.headers()
|
||||
, success: function (xhr) {
|
||||
treatmentData = xhr.map(function (treatment) {
|
||||
return moment.tz(treatment.created_at,zone).format('YYYY-MM-DD');
|
||||
});
|
||||
// unique it
|
||||
treatmentData = $.grep(treatmentData, function(v, k){
|
||||
return $.inArray(v ,treatmentData) === k;
|
||||
});
|
||||
treatmentData.sort(function(a, b) { return a > b; });
|
||||
}
|
||||
}).done(function () {
|
||||
//console.log('Notesfilter: ',treatmentData);
|
||||
for (var d=0; d<treatmentData.length; d++) {
|
||||
if (daystoshow[treatmentData[d]]) {
|
||||
daystoshow[treatmentData[d]]++;
|
||||
} else {
|
||||
daystoshow[treatmentData[d]] = 1;
|
||||
}
|
||||
}
|
||||
eventtypefilter();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
eventtypefilter();
|
||||
}
|
||||
}
|
||||
|
||||
//event type filter
|
||||
function eventtypefilter() {
|
||||
if ($('#rp_enableeventtype').is(':checked')) {
|
||||
matchesneeded++;
|
||||
var eventtype = $('#rp_eventtype').val();
|
||||
if (eventtype) {
|
||||
var treatmentData;
|
||||
var tquery = '?find[eventType]=/' + eventtype + '/i';
|
||||
$.ajax('/api/v1/treatments.json' + tquery + timerange, {
|
||||
headers: client.headers()
|
||||
, success: function (xhr) {
|
||||
treatmentData = xhr.map(function (treatment) {
|
||||
return moment.tz(treatment.created_at,zone).format('YYYY-MM-DD');
|
||||
});
|
||||
// unique it
|
||||
treatmentData = $.grep(treatmentData, function(v, k){
|
||||
return $.inArray(v ,treatmentData) === k;
|
||||
});
|
||||
treatmentData.sort(function(a, b) { return a > b; });
|
||||
}
|
||||
}).done(function () {
|
||||
//console.log('Eventtypefilter: ',treatmentData);
|
||||
for (var d=0; d<treatmentData.length; d++) {
|
||||
if (daystoshow[treatmentData[d]]) {
|
||||
daystoshow[treatmentData[d]]++;
|
||||
} else {
|
||||
daystoshow[treatmentData[d]] = 1;
|
||||
}
|
||||
}
|
||||
daysfilter();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
daysfilter();
|
||||
}
|
||||
}
|
||||
|
||||
function daysfilter() {
|
||||
matchesneeded++;
|
||||
Object.keys(daystoshow).forEach( function eachDay(d) {
|
||||
var day = moment.tz(d,zone).day();
|
||||
if (day===0 && $('#rp_su').is(':checked')) { daystoshow[d]++; }
|
||||
if (day===1 && $('#rp_mo').is(':checked')) { daystoshow[d]++; }
|
||||
if (day===2 && $('#rp_tu').is(':checked')) { daystoshow[d]++; }
|
||||
if (day===3 && $('#rp_we').is(':checked')) { daystoshow[d]++; }
|
||||
if (day===4 && $('#rp_th').is(':checked')) { daystoshow[d]++; }
|
||||
if (day===5 && $('#rp_fr').is(':checked')) { daystoshow[d]++; }
|
||||
if (day===6 && $('#rp_sa').is(':checked')) { daystoshow[d]++; }
|
||||
});
|
||||
countDays();
|
||||
addPreviousDayTreatments();
|
||||
display();
|
||||
}
|
||||
|
||||
function display() {
|
||||
var count = 0;
|
||||
sorteddaystoshow = [];
|
||||
$('#info').html('<b>'+translate('Loading')+' ...</b>');
|
||||
for (var d in daystoshow) {
|
||||
if (count < maxdays) {
|
||||
$('#info').append($('<div id="info-' + d + '"></div>'));
|
||||
count++;
|
||||
loadData(d, options, dataLoadedCallback);
|
||||
} else {
|
||||
$('#info').append($('<div>'+d+' '+translate('not displayed')+'.</div>'));
|
||||
delete daystoshow[d];
|
||||
}
|
||||
}
|
||||
if (count===0) {
|
||||
$('#info').html('<b>'+translate('Result is empty')+'</b>');
|
||||
$('#rp_show').css('display','');
|
||||
}
|
||||
}
|
||||
|
||||
var dayscount = 0;
|
||||
var loadeddays = 0;
|
||||
|
||||
function countDays() {
|
||||
for (var d in daystoshow) {
|
||||
if (daystoshow.hasOwnProperty(d)) {
|
||||
if (daystoshow[d]===matchesneeded) {
|
||||
if (dayscount < maxdays) {
|
||||
dayscount++;
|
||||
}
|
||||
} else {
|
||||
delete daystoshow[d];
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log('Total: ', daystoshow, 'Matches needed: ', matchesneeded, 'Will be loaded: ', dayscount);
|
||||
}
|
||||
|
||||
function addPreviousDayTreatments() {
|
||||
for (var d in daystoshow) {
|
||||
if (daystoshow.hasOwnProperty(d)) {
|
||||
var day = moment.tz(d,zone);
|
||||
var previous = day.subtract(1,'days');
|
||||
var formated = previous.format('YYYY-MM-DD');
|
||||
if (!daystoshow[formated]) {
|
||||
daystoshow[formated] = { treatmentsonly: true};
|
||||
console.log('Adding ' + formated + ' for loading treatments');
|
||||
dayscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log('Total: ', daystoshow, 'Matches needed: ', matchesneeded, 'Will be loaded: ', dayscount);
|
||||
}
|
||||
|
||||
function dataLoadedCallback (day) {
|
||||
loadeddays++;
|
||||
if (!daystoshow[day].treatmentsonly) {
|
||||
sorteddaystoshow.push(day);
|
||||
}
|
||||
if (loadeddays === dayscount) {
|
||||
sorteddaystoshow.sort();
|
||||
var from = sorteddaystoshow[0];
|
||||
var dFrom = sorteddaystoshow[0];
|
||||
var dTo = sorteddaystoshow[(sorteddaystoshow.length - 1)];
|
||||
|
||||
if (options.order === report_plugins.consts.ORDER_NEWESTONTOP) {
|
||||
sorteddaystoshow.reverse();
|
||||
}
|
||||
loadProfileSwitch(dFrom, function loadProfileSwitchCallback() {
|
||||
loadProfilesRange(dFrom, dTo, sorteddaystoshow.length, function loadProfilesCallback() {
|
||||
$('#info > b').html('<b>' + translate('Rendering') + ' ...</b>');
|
||||
window.setTimeout(function () {
|
||||
showreports(options);
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$('#rp_show').css('display','none');
|
||||
daystoshow = {};
|
||||
|
||||
datefilter();
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
function showreports(options) {
|
||||
// prepare some data used in more reports
|
||||
datastorage.allstatsrecords = [];
|
||||
datastorage.alldays = 0;
|
||||
sorteddaystoshow.forEach(function eachDay(day) {
|
||||
if (!daystoshow[day].treatmentsonly) {
|
||||
datastorage.allstatsrecords = datastorage.allstatsrecords.concat(datastorage[day].statsrecords);
|
||||
datastorage.alldays++;
|
||||
}
|
||||
});
|
||||
options.maxInsulinValue = maxInsulinValue;
|
||||
options.maxCarbsValue = maxCarbsValue;
|
||||
options.maxDailyCarbsValue = maxDailyCarbsValue;
|
||||
|
||||
datastorage.treatments = [];
|
||||
datastorage.devicestatus = [];
|
||||
datastorage.combobolusTreatments = [];
|
||||
datastorage.tempbasalTreatments = [];
|
||||
Object.keys(daystoshow).forEach( function eachDay(day) {
|
||||
datastorage.treatments = datastorage.treatments.concat(datastorage[day].treatments);
|
||||
datastorage.devicestatus = datastorage.devicestatus.concat(datastorage[day].devicestatus);
|
||||
datastorage.combobolusTreatments = datastorage.combobolusTreatments.concat(datastorage[day].combobolusTreatments);
|
||||
datastorage.tempbasalTreatments = datastorage.tempbasalTreatments.concat(datastorage[day].tempbasalTreatments);
|
||||
});
|
||||
datastorage.tempbasalTreatments = Nightscout.client.ddata.processDurations(datastorage.tempbasalTreatments);
|
||||
datastorage.treatments.sort(function sort(a, b) {return a.mills - b.mills; });
|
||||
|
||||
for (var d in daystoshow) {
|
||||
if (daystoshow.hasOwnProperty(d)) {
|
||||
if (daystoshow[d].treatmentsonly) {
|
||||
delete daystoshow[d];
|
||||
delete datastorage[d];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
report_plugins.eachPlugin(function (plugin) {
|
||||
// jquery plot doesn't draw to hidden div
|
||||
$('#'+plugin.name+'-placeholder').css('display','');
|
||||
|
||||
console.log('Drawing ',plugin.name);
|
||||
|
||||
var skipRender = false;
|
||||
|
||||
if (plugin.name == 'daytoday' && ! $('#daytoday').hasClass('selected')) skipRender = true;
|
||||
if (plugin.name == 'treatments' && ! $('#treatments').hasClass('selected')) skipRender = true;
|
||||
if (plugin.name == 'weektoweek' && ! $('#weektoweek').hasClass('selected')) skipRender = true;
|
||||
if (plugin.name == 'loopalyzer' && ! $('#loopalyzer').hasClass('selected')) skipRender = true;
|
||||
|
||||
if (skipRender) {
|
||||
console.log('Skipping ',plugin.name);
|
||||
} else {
|
||||
plugin.report(datastorage,sorteddaystoshow,options);
|
||||
}
|
||||
|
||||
if (!$('#'+plugin.name).hasClass('selected')) {
|
||||
$('#'+plugin.name+'-placeholder').css('display','none');
|
||||
}
|
||||
});
|
||||
|
||||
$('#info').html('');
|
||||
$('#rp_show').css('display','');
|
||||
}
|
||||
|
||||
function setDataRange(event,days) {
|
||||
$('#rp_to').val(moment().format('YYYY-MM-DD'));
|
||||
$('#rp_from').val(moment().add(-days+1, 'days').format('YYYY-MM-DD'));
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
function switchreport_handler(event) {
|
||||
var id = $(this).attr('id');
|
||||
|
||||
$('.menutab').removeClass('selected');
|
||||
$('#'+id).addClass('selected');
|
||||
|
||||
$('.tabplaceholder').css('display','none');
|
||||
$('#'+id+'-placeholder').css('display','');
|
||||
return maybePrevent(event);
|
||||
}
|
||||
|
||||
function loadData(day, options, callback) {
|
||||
// check for loaded data
|
||||
if ((options.openAps || options.predicted || options.iob || options.cob) && datastorage[day] && !datastorage[day].devicestatus.length) {
|
||||
// OpenAPS requested but data not loaded. Load anyway ...
|
||||
} else if (datastorage[day] && day !== moment().format('YYYY-MM-DD')) {
|
||||
callback(day);
|
||||
return;
|
||||
}
|
||||
// patientData = [actual, predicted, mbg, treatment, cal, devicestatusData];
|
||||
var data = {};
|
||||
var cgmData = []
|
||||
, mbgData = []
|
||||
, treatmentData = []
|
||||
, calData = []
|
||||
;
|
||||
var from;
|
||||
if (client.sbx.data.profile.getTimezone()) {
|
||||
from = moment(day).tz(client.sbx.data.profile.getTimezone()).startOf('day').format('x');
|
||||
} else {
|
||||
from = moment(day).startOf('day').format('x');
|
||||
}
|
||||
from = parseInt(from);
|
||||
var to = from + 1000 * 60 * 60 * 24;
|
||||
|
||||
function loadCGMData() {
|
||||
if (daystoshow[day].treatmentsonly) {
|
||||
data.sgv = [];
|
||||
data.mbg = [];
|
||||
data.cal = [];
|
||||
return $.Deferred().resolve();
|
||||
}
|
||||
$('#info-' + day).html('<b>'+translate('Loading CGM data of')+' '+day+' ...</b>');
|
||||
var query = '?find[date][$gte]='+from+'&find[date][$lt]='+to+'&count=10000';
|
||||
return $.ajax('/api/v1/entries.json'+query, {
|
||||
headers: client.headers()
|
||||
, success: function (xhr) {
|
||||
xhr.forEach(function (element) {
|
||||
if (element) {
|
||||
if (element.mbg) {
|
||||
mbgData.push({
|
||||
y: element.mbg
|
||||
, mills: element.date
|
||||
, d: element.dateString
|
||||
, device: element.device
|
||||
});
|
||||
} else if (element.sgv) {
|
||||
cgmData.push({
|
||||
y: element.sgv
|
||||
, mills: element.date
|
||||
, d: element.dateString
|
||||
, device: element.device
|
||||
, filtered: element.filtered
|
||||
, unfiltered: element.unfiltered
|
||||
, noise: element.noise
|
||||
, rssi: element.rssi
|
||||
, sgv: element.sgv
|
||||
});
|
||||
} else if (element.type === 'cal') {
|
||||
calData.push({
|
||||
mills: element.date + 1
|
||||
, d: element.dateString
|
||||
, scale: element.scale
|
||||
, intercept: element.intercept
|
||||
, slope: element.slope
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// sometimes cgm contains duplicates. uniq it.
|
||||
data.sgv = cgmData.slice();
|
||||
data.sgv.sort(function(a, b) { return a.mills - b.mills; });
|
||||
var lastDate = 0;
|
||||
data.sgv = data.sgv.filter(function(d) {
|
||||
var ok = (lastDate + ONE_MIN_IN_MS) <= d.mills;
|
||||
lastDate = d.mills;
|
||||
if (!ok) { console.log("itm",JSON.stringify(d)); }
|
||||
return ok;
|
||||
});
|
||||
data.mbg = mbgData.slice();
|
||||
data.mbg.sort(function(a, b) { return a.mills - b.mills; });
|
||||
data.cal = calData.slice();
|
||||
data.cal.sort(function(a, b) { return a.mills - b.mills; });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadTreatmentData() {
|
||||
if (!datastorage.profileSwitchTreatments)
|
||||
datastorage.profileSwitchTreatments = [];
|
||||
$('#info-' + day).html('<b>'+translate('Loading treatments data of')+' '+day+' ...</b>');
|
||||
var tquery = '?find[created_at][$gte]='+new Date(from).toISOString()+'&find[created_at][$lt]='+new Date(to).toISOString()+'&count=1000';
|
||||
return $.ajax('/api/v1/treatments.json'+tquery, {
|
||||
headers: client.headers()
|
||||
, cache: false
|
||||
, success: function (xhr) {
|
||||
treatmentData = xhr.map(function (treatment) {
|
||||
var timestamp = new Date(treatment.timestamp || treatment.created_at);
|
||||
treatment.mills = timestamp.getTime();
|
||||
return treatment;
|
||||
});
|
||||
data.treatments = treatmentData.slice();
|
||||
data.treatments.sort(function(a, b) { return a.mills - b.mills; });
|
||||
// filter 'Combo Bolus' events
|
||||
data.combobolusTreatments = data.treatments.filter( function filterComboBoluses(t) {
|
||||
return t.eventType === 'Combo Bolus';
|
||||
});
|
||||
// filter temp basal treatments
|
||||
data.tempbasalTreatments = data.treatments.filter(function filterTempBasals(t) {
|
||||
return t.eventType === 'Temp Basal';
|
||||
});
|
||||
// filter profile switch treatments
|
||||
var profileSwitch = data.treatments.filter(function filterProfileSwitch(t) {
|
||||
return t.eventType === 'Profile Switch';
|
||||
});
|
||||
datastorage.profileSwitchTreatments = datastorage.profileSwitchTreatments.concat(profileSwitch);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadDevicestatusData() {
|
||||
if (daystoshow[day].treatmentsonly) {
|
||||
data.devicestatus = [];
|
||||
return $.Deferred().resolve();
|
||||
}
|
||||
if (options.iob || options.cob || options.openAps || options.predicted) {
|
||||
$('#info-' + day).html('<b>'+translate('Loading device status data of')+' '+day+' ...</b>');
|
||||
var tquery = '?find[created_at][$gte]=' + new Date(from).toISOString() + '&find[created_at][$lt]=' + new Date(to).toISOString() + '&count=10000';
|
||||
return $.ajax('/api/v1/devicestatus.json'+tquery, {
|
||||
headers: client.headers()
|
||||
, success: function (xhr) {
|
||||
data.devicestatus = xhr.map(function (devicestatus) {
|
||||
devicestatus.mills = new Date(devicestatus.timestamp || devicestatus.created_at).getTime();
|
||||
return devicestatus;
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
data.devicestatus = [];
|
||||
return $.Deferred().resolve();
|
||||
}
|
||||
}
|
||||
|
||||
$.when(loadCGMData(), loadTreatmentData(), loadDevicestatusData()).done(function () {
|
||||
$('#info-' + day).html('<b>'+translate('Processing data of')+' '+day+' ...</b>');
|
||||
processData(data, day, options, callback);
|
||||
});
|
||||
}
|
||||
|
||||
function loadProfileSwitch (from, callback) {
|
||||
$('#info > b').html('<b>'+translate('Loading profile switch data') + ' ...</b>');
|
||||
var tquery = '?find[eventType]=Profile Switch' + '&find[created_at][$lte]=' + new Date(from).toISOString() + '&count=1';
|
||||
$.ajax('/api/v1/treatments.json'+tquery, {
|
||||
headers: client.headers()
|
||||
, success: function (xhr) {
|
||||
var treatmentData = xhr.map(function (treatment) {
|
||||
var timestamp = new Date(treatment.timestamp || treatment.created_at);
|
||||
treatment.mills = timestamp.getTime();
|
||||
return treatment;
|
||||
});
|
||||
if (!datastorage.profileSwitchTreatments)
|
||||
datastorage.profileSwitchTreatments = [];
|
||||
datastorage.profileSwitchTreatments = datastorage.profileSwitchTreatments.concat(treatmentData);
|
||||
datastorage.profileSwitchTreatments.sort(function(a, b) { return a.mills - b.mills; });
|
||||
}
|
||||
}).done(function () {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function loadProfiles(callback) {
|
||||
$('#info > b').html('<b>'+translate('Loading profiles') + ' ...</b>');
|
||||
$.ajax('/api/v1/profile.json', {
|
||||
headers: client.headers()
|
||||
, success: function (records) {
|
||||
datastorage.profiles = records;
|
||||
}
|
||||
, error: function () {
|
||||
datastorage.profiles = [];
|
||||
}
|
||||
}).done(callback);
|
||||
}
|
||||
|
||||
function loadProfilesRange (dateFrom, dateTo, dayCount, callback) {
|
||||
$('#info > b').html('<b>' + translate('Loading profile range') + ' ...</b>');
|
||||
|
||||
$.when(
|
||||
loadProfilesRangeCore(dateFrom, dateTo, dayCount),
|
||||
loadProfilesRangePrevious(dateFrom),
|
||||
loadProfilesRangeNext(dateTo)
|
||||
)
|
||||
.done(callback)
|
||||
.fail(function () {
|
||||
datastorage.profiles = [];
|
||||
});
|
||||
}
|
||||
|
||||
function loadProfilesRangeCore (dateFrom, dateTo, dayCount) {
|
||||
$('#info > b').html('<b>' + translate('Loading core profiles') + ' ...</b>');
|
||||
|
||||
//The results must be returned in descending order to work with key logic in routines such as getCurrentProfile
|
||||
var tquery = '?find[startDate][$gte]=' + new Date(dateFrom).toISOString() + '&find[startDate][$lte]=' + new Date(dateTo).toISOString() + '&sort[startDate]=-1&count=1000';
|
||||
|
||||
return $.ajax('/api/v1/profiles' + tquery, {
|
||||
headers: client.headers(),
|
||||
async: false,
|
||||
success: function (records) {
|
||||
datastorage.profiles = records;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadProfilesRangePrevious (dateFrom) {
|
||||
$('#info > b').html('<b>' + translate('Loading previous profile') + ' ...</b>');
|
||||
|
||||
//Find first one before the start date and add to datastorage.profiles
|
||||
var tquery = '?find[startDate][$lt]=' + new Date(dateFrom).toISOString() + '&sort[startDate]=-1&count=1';
|
||||
|
||||
return $.ajax('/api/v1/profiles' + tquery, {
|
||||
headers: client.headers(),
|
||||
async: false,
|
||||
success: function (records) {
|
||||
records.forEach(function (r) {
|
||||
datastorage.profiles.push(r);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadProfilesRangeNext (dateTo) {
|
||||
$('#info > b').html('<b>' + translate('Loading next profile') + ' ...</b>');
|
||||
|
||||
//Find first one after the end date and add to datastorage.profiles
|
||||
var tquery = '?find[startDate][$gt]=' + new Date(dateTo).toISOString() + '&sort[startDate]=1&count=1';
|
||||
|
||||
return $.ajax('/api/v1/profiles' + tquery, {
|
||||
headers: client.headers(),
|
||||
async: false,
|
||||
success: function (records) {
|
||||
records.forEach(function (r) {
|
||||
//must be inserted as top to maintain profiles being sorted by date in descending order
|
||||
datastorage.profiles.unshift(r);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function processData(data, day, options, callback) {
|
||||
if (daystoshow[day].treatmentsonly) {
|
||||
datastorage[day] = data;
|
||||
$('#info-' + day).html('');
|
||||
callback(day);
|
||||
return;
|
||||
}
|
||||
// treatments
|
||||
data.dailyCarbs = 0;
|
||||
data.dailyProtein = 0;
|
||||
data.dailyFat = 0;
|
||||
|
||||
data.treatments.forEach(function (d) {
|
||||
if (parseFloat(d.insulin) > maxInsulinValue) {
|
||||
maxInsulinValue = parseFloat(d.insulin);
|
||||
}
|
||||
if (parseFloat(d.carbs) > maxCarbsValue) {
|
||||
maxCarbsValue = parseFloat(d.carbs);
|
||||
}
|
||||
if (d.carbs) {
|
||||
data.dailyCarbs += Number(d.carbs);
|
||||
}
|
||||
if (d.protein) {
|
||||
data.dailyProtein += Number(d.protein);
|
||||
}
|
||||
if (d.fat) {
|
||||
data.dailyFat += Number(d.fat);
|
||||
}
|
||||
});
|
||||
if (data.dailyCarbs > maxDailyCarbsValue) {
|
||||
maxDailyCarbsValue = data.dailyCarbs;
|
||||
}
|
||||
|
||||
var cal = data.cal[data.cal.length-1];
|
||||
var temp1 = [ ];
|
||||
var rawbg = client.rawbg;
|
||||
if (cal) {
|
||||
temp1 = data.sgv.map(function (entry) {
|
||||
entry.mgdl = entry.y; // value names changed from enchilada
|
||||
var rawBg = rawbg.calc(entry, cal);
|
||||
return { mills: entry.mills, date: new Date(entry.mills - 2 * 1000), y: rawBg, sgv: client.utils.scaleMgdl(rawBg), color: 'gray', type: 'rawbg', filtered: entry.filtered, unfiltered: entry.unfiltered };
|
||||
}).filter(function(entry) { return entry.y > 0});
|
||||
}
|
||||
var temp2 = data.sgv.map(function (obj) {
|
||||
return { mills: obj.mills, date: new Date(obj.mills), y: obj.y, sgv: client.utils.scaleMgdl(obj.y), color: sgvToColor(client.utils.scaleMgdl(obj.y),options), type: 'sgv', noise: obj.noise, filtered: obj.filtered, unfiltered: obj.unfiltered};
|
||||
});
|
||||
data.sgv = [].concat(temp1, temp2);
|
||||
|
||||
//Add MBG's also, pretend they are SGV's
|
||||
data.sgv = data.sgv.concat(data.mbg.map(function (obj) { return { date: new Date(obj.mills), y: obj.y, sgv: client.utils.scaleMgdl(obj.y), color: 'red', type: 'mbg', device: obj.device } }));
|
||||
|
||||
// make sure data range will be exactly 24h
|
||||
var from;
|
||||
if (client.sbx.data.profile.getTimezone()) {
|
||||
from = moment(day).tz(client.sbx.data.profile.getTimezone()).startOf('day').toDate();
|
||||
} else {
|
||||
from = moment(day).startOf('day').toDate();
|
||||
}
|
||||
var to = new Date(from.getTime() + 1000 * 60 * 60 * 24);
|
||||
data.sgv.push({ date: from, y: 40, sgv: 40, color: 'transparent', type: 'rawbg'});
|
||||
data.sgv.push({ date: to, y: 40, sgv: 40, color: 'transparent', type: 'rawbg'});
|
||||
|
||||
// clear error data. we don't need it to display them
|
||||
data.sgv = data.sgv.filter(function (d) {
|
||||
if (d.y < 39) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
data.sgv = data.sgv.map(function eachSgv (sgv) {
|
||||
var status = _.find(data.devicestatus, function (d) {
|
||||
return d.mills >= sgv.mills && d.mills < sgv.mills + 5 * 60 * 1000;
|
||||
});
|
||||
|
||||
if (status && status.openaps) {
|
||||
sgv.openaps = status.openaps;
|
||||
}
|
||||
return sgv;
|
||||
});
|
||||
|
||||
// for other reports
|
||||
data.statsrecords = data.sgv.filter(function(r) {
|
||||
if (r.type) {
|
||||
return r.type === 'sgv';
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}).map(function (r) {
|
||||
var ret = {};
|
||||
ret.sgv = parseFloat(r.sgv);
|
||||
ret.bgValue = parseInt(r.y);
|
||||
ret.displayTime = r.date;
|
||||
return ret;
|
||||
});
|
||||
|
||||
|
||||
datastorage[day] = data;
|
||||
$('#info-' + day).html('');
|
||||
callback(day);
|
||||
}
|
||||
|
||||
function maybePrevent(event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user