From c7fecfe0bbe679521d5b4a9cc3a6461ae2264ae3 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 3 Oct 2017 12:28:41 +0800 Subject: [PATCH 1/5] MDL-59106 tool_analytics: fixed string describing 'onlycli' setting --- admin/tool/analytics/lang/en/tool_analytics.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/tool/analytics/lang/en/tool_analytics.php b/admin/tool/analytics/lang/en/tool_analytics.php index df38a14e7ae..3cdb7232e9e 100644 --- a/admin/tool/analytics/lang/en/tool_analytics.php +++ b/admin/tool/analytics/lang/en/tool_analytics.php @@ -30,7 +30,7 @@ $string['bettercli'] = 'Evaluating models and generating predictions may involve $string['cantguessstartdate'] = 'Can\'t guess the start date'; $string['cantguessenddate'] = 'Can\'t guess the end date'; $string['clienablemodel'] = 'You can enable the model by selecting a time-splitting method by its ID. Note that you can also enable it later using the web interface (\'none\' to exit).'; -$string['clievaluationandpredictions'] = 'A cron task iterates through enabled models and gets predictions. Models evaluation via command line is disabled. You can allow these processes to be executed manually via web interface by enabling \'onlycli\' analytics setting'; +$string['clievaluationandpredictions'] = 'A scheduled task iterates through enabled models and gets predictions. Models evaluation via the web interface is disabled. You can allow these processes to be executed manually via the web interface by disabling the \'onlycli\' analytics setting'; $string['editmodel'] = 'Edit "{$a}" model'; $string['edittrainedwarning'] = 'This model has already been trained. Note that changing its indicators or its time-splitting method will delete its previous predictions and start generating new predictions.'; $string['enabled'] = 'Enabled'; From 235da74e0b18cc2946723d791e8035ad8dd3faa9 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 12 Sep 2017 16:37:37 +0800 Subject: [PATCH 2/5] MDL-59106 core: added fields to 'analytics_predictions' table --- lib/db/install.xml | 2 ++ lib/db/upgrade.php | 22 ++++++++++++++++++++++ version.php | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/db/install.xml b/lib/db/install.xml index bd36ac76690..c174f8ae5a3 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -3618,6 +3618,8 @@ + + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index d0fb99f05b2..3742d13e017 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2601,5 +2601,27 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2017092900.00); } + if ($oldversion < 2017100601.00) { + // Define field 'timestart' to be added to 'analytics_predictions'. + $table = new xmldb_table('analytics_predictions'); + $field = new xmldb_field('timestart', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'timecreated'); + + // Conditionally launch add field 'timestart'. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Define field 'timeend' to be added to 'analytics_predictions'. + $field = new xmldb_field('timeend', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'timestart'); + + // Conditionally launch add field 'timeend'. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Main savepoint reached. + upgrade_main_savepoint(true, 2017100601.00); + } + return true; } diff --git a/version.php b/version.php index a8c58ddd6fb..fb6b14cd78b 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2017100600.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2017100601.00; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. From f87174dcc230cb585cccdc8af1afa92dc5ebc57a Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Thu, 5 Oct 2017 17:45:11 +0800 Subject: [PATCH 3/5] MDL-59106 analytics: store the 'timestart' and 'timeend' values --- analytics/classes/model.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/analytics/classes/model.php b/analytics/classes/model.php index 4bf9ea1b9db..7ccb1cce601 100644 --- a/analytics/classes/model.php +++ b/analytics/classes/model.php @@ -932,8 +932,6 @@ class model { * @return \context */ protected function prepare_prediction_record($sampleid, $rangeindex, $prediction, $predictionscore, $calculations) { - global $DB; - $context = $this->get_analyser()->sample_access_context($sampleid); $record = new \stdClass(); @@ -946,6 +944,15 @@ class model { $record->calculations = $calculations; $record->timecreated = time(); + $analysable = $this->get_analyser()->get_sample_analysable($sampleid); + $timesplitting = $this->get_time_splitting(); + $timesplitting->set_analysable($analysable); + $range = $timesplitting->get_range_by_index($rangeindex); + if ($range) { + $record->timestart = $range['start']; + $record->timeend = $range['end']; + } + return array($record, $context); } From c614073940925880dd7d6c843dee7018d93215f7 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 6 Oct 2017 17:20:55 +0800 Subject: [PATCH 4/5] MDL-59106 report_insights: show time created and time range used --- report/insights/classes/output/insight.php | 23 ++++++-- .../insights/classes/output/insights_list.php | 28 ++++++++- report/insights/lang/en/report_insights.php | 3 + report/insights/templates/insight.mustache | 17 +----- .../templates/insight_details.mustache | 34 +++++++++-- .../insights/templates/insights_list.mustache | 59 ++++++++++++------- 6 files changed, 115 insertions(+), 49 deletions(-) diff --git a/report/insights/classes/output/insight.php b/report/insights/classes/output/insight.php index 525129fd8f0..d0ffa6e2114 100644 --- a/report/insights/classes/output/insight.php +++ b/report/insights/classes/output/insight.php @@ -71,10 +71,23 @@ class insight implements \renderable, \templatable { * @return \stdClass */ public function export_for_template(\renderer_base $output) { + // Get the prediction data. + $predictiondata = $this->prediction->get_prediction_data(); $data = new \stdClass(); $data->insightname = format_string($this->model->get_target()->get_name()); + // Get the details. + $data->timecreated = userdate($predictiondata->timecreated); + $data->timerange = ''; + + if (!empty($predictiondata->timestart) && !empty($predictiondata->timeend)) { + $timerange = new \stdClass(); + $timerange->timestart = userdate($predictiondata->timestart); + $timerange->timeend = userdate($predictiondata->timeend); + $data->timerange = get_string('timerangewithdata', 'report_insights', $timerange); + } + // Sample info (determined by the analyser). list($data->sampledescription, $samplerenderable) = $this->model->prediction_sample_description($this->prediction); @@ -84,10 +97,10 @@ class insight implements \renderable, \templatable { } // Prediction info. - $predictedvalue = $this->prediction->get_prediction_data()->prediction; - $predictionid = $this->prediction->get_prediction_data()->id; + $predictedvalue = $predictiondata->prediction; + $predictionid = $predictiondata->id; $data->predictiondisplayvalue = $this->model->get_target()->get_display_value($predictedvalue); - list($data->style, $data->outcomeicon) = $this->get_calculation_display($this->model->get_target(), + list($data->style, $data->outcomeicon) = self::get_calculation_display($this->model->get_target(), floatval($predictedvalue), $output); $actions = $this->model->get_target()->prediction_actions($this->prediction, $this->includedetailsaction); @@ -124,7 +137,7 @@ class insight implements \renderable, \templatable { $obj = new \stdClass(); $obj->name = call_user_func(array($calculation->indicator, 'get_name')); $obj->displayvalue = $calculation->indicator->get_display_value($calculation->value, $calculation->subtype); - list($obj->style, $obj->outcomeicon) = $this->get_calculation_display($calculation->indicator, + list($obj->style, $obj->outcomeicon) = self::get_calculation_display($calculation->indicator, floatval($calculation->value), $output, $calculation->subtype); $data->calculations[] = $obj; @@ -149,7 +162,7 @@ class insight implements \renderable, \templatable { * @param string|false $subtype * @return array The style as 'success', 'info', 'warning' or 'danger' and pix_icon */ - protected function get_calculation_display(\core_analytics\calculable $calculable, $value, $output, $subtype = false) { + public static function get_calculation_display(\core_analytics\calculable $calculable, $value, $output, $subtype = false) { $outcome = $calculable->get_calculation_outcome($value, $subtype); switch ($outcome) { case \core_analytics\calculable::OUTCOME_NEUTRAL: diff --git a/report/insights/classes/output/insights_list.php b/report/insights/classes/output/insights_list.php index 1da683eb2b7..158e8bebb1c 100644 --- a/report/insights/classes/output/insights_list.php +++ b/report/insights/classes/output/insights_list.php @@ -95,17 +95,39 @@ class insights_list implements \renderable, \templatable { if ($this->model->uses_insights()) { $predictionsdata = $this->model->get_predictions($this->context, true, $this->page, $this->perpage); - $data->insights = array(); + $data->predictions = array(); + $predictionvalues = array(); + $insights = array(); if ($predictionsdata) { list($total, $predictions) = $predictionsdata; foreach ($predictions as $prediction) { + $predictedvalue = $prediction->get_prediction_data()->prediction; + + // Only need to fill this data once. + if (!isset($predictionvalues[$predictedvalue])) { + $preddata = array(); + $preddata['predictiondisplayvalue'] = $this->model->get_target()->get_display_value($predictedvalue); + list($preddata['style'], $preddata['outcomeicon']) = + insight::get_calculation_display($this->model->get_target(), $predictedvalue, $output); + $predictionvalues[$predictedvalue] = $preddata; + } + $insightrenderable = new \report_insights\output\insight($prediction, $this->model, true); - $data->insights[] = $insightrenderable->export_for_template($output); + $insights[$predictedvalue][] = $insightrenderable->export_for_template($output); + } + + // Ok, now we have all the data we want, put it into a format that mustache can handle. + foreach ($predictionvalues as $key => $prediction) { + if (isset($insights[$key])) { + $prediction['insights'] = $insights[$key]; + } + + $data->predictions[] = $prediction; } } - if (empty($data->insights) && $this->page == 0) { + if (empty($insights) && $this->page == 0) { if ($this->model->any_prediction_obtained()) { $data->noinsights = get_string('noinsights', 'analytics'); } else { diff --git a/report/insights/lang/en/report_insights.php b/report/insights/lang/en/report_insights.php index a69600b98cf..68827ab9b36 100644 --- a/report/insights/lang/en/report_insights.php +++ b/report/insights/lang/en/report_insights.php @@ -40,4 +40,7 @@ $string['prediction'] = 'Prediction'; $string['predictioncalculations'] = 'Indicator calculations'; $string['predictiondetails'] = 'Prediction details'; $string['nodetailsavailable'] = 'No prediction details are relevant.'; +$string['timecreated'] = 'Time predicted'; +$string['timerange'] = 'Time range'; +$string['timerangewithdata'] = '{$a->timestart} to {$a->timeend}'; $string['selectotherinsights'] = 'Select other insights...'; diff --git a/report/insights/templates/insight.mustache b/report/insights/templates/insight.mustache index ad24102fc3e..693549d7f50 100644 --- a/report/insights/templates/insight.mustache +++ b/report/insights/templates/insight.mustache @@ -31,29 +31,16 @@ Example context (json): { "sampleimage": "Link", - "sampledescription": "Sample description", - "style": "success", - "outcomeicon": { - "attributes": [ - {"name": "src", "value": "https://moodle.org/logo/moodle-logo.svg" } - ] - }, - "predictiondisplayvalue": "This dev will understand it" + "sampledescription": "Sample description" } }} - + {{#sampleimage}} {{{sampleimage}}} {{/sampleimage}} {{{sampledescription}}} - - {{#outcomeicon}} - {{> core/pix_icon}} - {{/outcomeicon}} - {{predictiondisplayvalue}} - {{#actions}} {{> core/action_menu}} diff --git a/report/insights/templates/insight_details.mustache b/report/insights/templates/insight_details.mustache index 72940c9e1fb..f5a6493d263 100644 --- a/report/insights/templates/insight_details.mustache +++ b/report/insights/templates/insight_details.mustache @@ -31,6 +31,8 @@ Example context (json): { "insightname": "Best insight ever", + "timecreated": "Thursday, 5 October 2017, 4:16 PM", + "timerange": "Monday, 4 September 2017, 6:00 PM to Thursday, 5 October 2017, 12:00 AM", "sampleimage": "Link", "sampledescription": "Sample description", "style": "success", @@ -73,11 +75,18 @@

{{#str}}insightprediction, report_insights, {{insightname}} {{/str}}

- + - - + @@ -86,8 +95,23 @@
{{#str}}insight, report_insights{{/str}} + {{#str}}prediction, report_insights{{/str}}: + + {{#outcomeicon}} + {{> core/pix_icon}} + {{/outcomeicon}} + {{predictiondisplayvalue}} + +
{{#str}}name{{/str}}{{#str}}prediction, report_insights{{/str}}{{#str}}name{{/str}} {{#str}}actions{{/str}}
- +
+ + + + + + {{#timerange}} + + + + + {{/timerange}} + +
{{#str}}predictiondetails, report_insights{{/str}}
{{#str}}timecreated, report_insights{{/str}}{{timecreated}}
{{#str}}timerange, report_insights{{/str}}{{.}}
+ + @@ -99,7 +123,7 @@ - + {{/calculations}}
{{#str}}predictioncalculations, report_insights{{/str}}
{{#str}}indicator, report_insights{{/str}}
{{name}} {{#outcomeicon}}{{> core/pix_icon}}{{/outcomeicon}} {{displayvalue}}
diff --git a/report/insights/templates/insights_list.mustache b/report/insights/templates/insights_list.mustache index ecb26899d65..2c6c2008252 100644 --- a/report/insights/templates/insights_list.mustache +++ b/report/insights/templates/insights_list.mustache @@ -31,27 +31,35 @@ Example context (json): { "insightname": "Best insight ever", - "insights": [ + "predictions": [ { - "sampleimage": "Link", - "sampledescription": "Sample description", + "predictiondisplayvalue": "This dev will understand it", "style": "success", "outcomeicon": { "attributes": [ {"name": "src", "value": "https://moodle.org/logo/moodle-logo.svg" } ] }, - "predictiondisplayvalue": "This dev will understand it" + "insights": [ + { + "sampleimage": "Link", + "sampledescription": "Sample description" + } + ] }, { - "sampleimage": "Any renderable", - "sampledescription": "Another sample description", + "predictiondisplayvalue": "This dev will not understand it", "style": "danger", "outcomeicon": { "attributes": [ {"name": "src", "value": "https://moodle.org/logo/moodle-logo.svg" } ] }, - "predictiondisplayvalue": "This dev will not understand it" + "insights": [ + { + "sampleimage": "Any renderable", + "sampledescription": "Another sample description" + } + ] } ], "noinsights": false @@ -67,21 +75,30 @@

{{{insightname}}}

{{^noinsights}} {{{ pagingbar }}} - - - - - - - - - - - {{#insights}} +{{#predictions}} +
{{#str}}insights, report_insights{{/str}}
{{#str}}name{{/str}}{{#str}}prediction, report_insights{{/str}}{{#str}}actions{{/str}}
+ + + + + + + + {{#insights}} + {{> report_insights/insight}} - {{/insights}} - -
+ {{#str}}prediction, report_insights{{/str}}: + + {{#outcomeicon}} + {{> core/pix_icon}} + {{/outcomeicon}} + {{predictiondisplayvalue}} + +
{{#str}}name{{/str}}{{#str}}actions{{/str}}
+ + {{/insights}} + +{{/predictions}} {{{ pagingbar }}} {{/noinsights}} {{#noinsights}} From f473958e49176cdf16e683a3895c06d8d0780404 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Fri, 6 Oct 2017 17:13:15 +0800 Subject: [PATCH 5/5] MDL-59106 theme_bootstrapbase: removed unnecessary template overrides --- .../report_insights/insight.mustache | 62 ---------- .../report_insights/insight_details.mustache | 108 ------------------ .../report_insights/insights_list.mustache | 91 --------------- 3 files changed, 261 deletions(-) delete mode 100644 theme/bootstrapbase/templates/report_insights/insight.mustache delete mode 100644 theme/bootstrapbase/templates/report_insights/insight_details.mustache delete mode 100644 theme/bootstrapbase/templates/report_insights/insights_list.mustache diff --git a/theme/bootstrapbase/templates/report_insights/insight.mustache b/theme/bootstrapbase/templates/report_insights/insight.mustache deleted file mode 100644 index 3e152a6cc38..00000000000 --- a/theme/bootstrapbase/templates/report_insights/insight.mustache +++ /dev/null @@ -1,62 +0,0 @@ -{{! - This file is part of Moodle - http://moodle.org/ - - Moodle is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Moodle is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Moodle. If not, see . -}} -{{! - @template report_insights/insight - - Template for a insight. - - Classes required for JS: - * none - - Data attributes required for JS: - * none - - Context variables required for this template: - * none - - Example context (json): - { - "sampleimage": "Link", - "sampledescription": "Sample description", - "style": "success", - "outcomeicon": { - "attributes": [ - {"name": "src", "value": "https://moodle.org/logo/moodle-logo.svg" } - ] - }, - "predictiondisplayvalue": "This dev will understand it" - } -}} - - - {{#sampleimage}} - {{{sampleimage}}} - {{/sampleimage}} - {{{sampledescription}}} - - - {{#outcomeicon}} - {{> core/pix_icon}} - {{/outcomeicon}} - {{predictiondisplayvalue}} - - - {{#actions}} - {{> core/action_menu}} - {{/actions}} - - diff --git a/theme/bootstrapbase/templates/report_insights/insight_details.mustache b/theme/bootstrapbase/templates/report_insights/insight_details.mustache deleted file mode 100644 index 65dda0fa0dd..00000000000 --- a/theme/bootstrapbase/templates/report_insights/insight_details.mustache +++ /dev/null @@ -1,108 +0,0 @@ -{{! - This file is part of Moodle - http://moodle.org/ - - Moodle is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Moodle is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Moodle. If not, see . -}} -{{! - @template report_insights/insight_details - - Actions panel at the bottom of the assignment grading UI. - - Classes required for JS: - * none - - Data attributes required for JS: - * none - - Context variables required for this template: - * none - - Example context (json): - { - "insightname": "Best insight ever", - "sampleimage": "Link", - "sampledescription": "Sample description", - "style": "success", - "outcomeicon": { - "attributes": [ - {"name": "src", "value": "https://moodle.org/logo/moodle-logo.svg" } - ] - }, - "predictiondisplayvalue": "This dev will understand it", - "calculations": [ - { - "style": "success", - "outcomeicon": { - "attributes": [ - {"name": "src", "value": "https://moodle.org/logo/moodle-logo.svg" } - ] - }, - "name": "Indicator 1", - "displayvalue": "yes" - }, { - "style": "info", - "name": "Indicator 2", - "displayvalue": "20%" - }, { - "style": "", - "name": "Indicator 2", - "displayvalue": "20%" - }, { - "style": "warning", - "name": "Indicator 2", - "displayvalue": "20%" - }, { - "style": "danger", - "name": "Indicator 2", - "displayvalue": "20%" - } - ] - } -}} - -

{{#str}}insightprediction, report_insights, {{insightname}} {{/str}}

- - - - - - - - - - - {{> report_insights/insight}} - -
{{#str}}insight, report_insights{{/str}}
{{#str}}name{{/str}}{{#str}}prediction, report_insights{{/str}}{{#str}}actions{{/str}}
- - - - - - - - - - - {{#calculations}} - - - - - {{/calculations}} - -
{{#str}}predictiondetails, report_insights{{/str}}
{{#str}}indicator, report_insights{{/str}}{{#str}}calculatedvalue, report_insights{{/str}}
{{name}}{{#outcomeicon}}{{> core/pix_icon}}{{/outcomeicon}} {{displayvalue}}
-{{#nocalculations}} - {{> core/notification_info}} -{{/nocalculations}} diff --git a/theme/bootstrapbase/templates/report_insights/insights_list.mustache b/theme/bootstrapbase/templates/report_insights/insights_list.mustache deleted file mode 100644 index ecb26899d65..00000000000 --- a/theme/bootstrapbase/templates/report_insights/insights_list.mustache +++ /dev/null @@ -1,91 +0,0 @@ -{{! - This file is part of Moodle - http://moodle.org/ - - Moodle is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Moodle is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Moodle. If not, see . -}} -{{! - @template report_insights/insights_list - - Template for the insights list. - - Classes required for JS: - * none - - Data attributes required for JS: - * none - - Context variables required for this template: - * none - - Example context (json): - { - "insightname": "Best insight ever", - "insights": [ - { - "sampleimage": "Link", - "sampledescription": "Sample description", - "style": "success", - "outcomeicon": { - "attributes": [ - {"name": "src", "value": "https://moodle.org/logo/moodle-logo.svg" } - ] - }, - "predictiondisplayvalue": "This dev will understand it" - }, { - "sampleimage": "Any renderable", - "sampledescription": "Another sample description", - "style": "danger", - "outcomeicon": { - "attributes": [ - {"name": "src", "value": "https://moodle.org/logo/moodle-logo.svg" } - ] - }, - "predictiondisplayvalue": "This dev will not understand it" - } - ], - "noinsights": false - } -}} - -{{#modelselector}} -
- {{> core/single_select}} -
-{{/modelselector}} - -

{{{insightname}}}

-{{^noinsights}} -{{{ pagingbar }}} - - - - - - - - - - - {{#insights}} - {{> report_insights/insight}} - {{/insights}} - -
{{#str}}insights, report_insights{{/str}}
{{#str}}name{{/str}}{{#str}}prediction, report_insights{{/str}}{{#str}}actions{{/str}}
-{{{ pagingbar }}} -{{/noinsights}} -{{#noinsights}} -
- {{> core/notification_info}} -
-{{/noinsights}}