diff --git a/admin/tool/analytics/amd/build/model.min.js b/admin/tool/analytics/amd/build/model.min.js new file mode 100644 index 0000000000000..e9e2e3c4decba --- /dev/null +++ b/admin/tool/analytics/amd/build/model.min.js @@ -0,0 +1 @@ +define(["jquery","core/str","core/log","core/notification","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f){var g={clear:{title:{key:"clearpredictions",component:"tool_analytics"},body:{key:"clearmodelpredictions",component:"tool_analytics"}}},h=function(b){return a(b.closest("tr")[0]).find("span.target-name").text()};return{confirmAction:function(i,j){a('[data-action-id="'+i+'"]').on("click",function(i){i.preventDefault();var k=a(i.currentTarget);if("undefined"==typeof g[j])return void c.error('Action "'+j+'" is not allowed.');var l=[g[j].title,g[j].body];l[1].param=h(k);var m=b.get_strings(l),n=e.create({type:e.types.SAVE_CANCEL});a.when(m,n).then(function(a,b){return b.setTitle(a[0]),b.setBody(a[1]),b.setSaveButtonText(a[0]),b.getRoot().on(f.save,function(){window.location.href=k.attr("href")}),b.show(),b}).fail(d.exception)})}}}); \ No newline at end of file diff --git a/admin/tool/analytics/amd/src/model.js b/admin/tool/analytics/amd/src/model.js new file mode 100644 index 0000000000000..891343143ff45 --- /dev/null +++ b/admin/tool/analytics/amd/src/model.js @@ -0,0 +1,94 @@ +// 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 . + +/** + * AMD module for model actions confirmation. + * + * @module tool_analytics/model + * @copyright 2017 David Monllao + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['jquery', 'core/str', 'core/log', 'core/notification', 'core/modal_factory', 'core/modal_events'], + function($, Str, log, Notification, ModalFactory, ModalEvents) { + + /** + * List of actions that require confirmation and confirmation message. + */ + var actionsList = { + clear: { + title: { + key: 'clearpredictions', + component: 'tool_analytics' + }, body: { + key: 'clearmodelpredictions', + component: 'tool_analytics' + } + + } + }; + + /** + * Returns the model name. + * + * @param {Object} actionItem The action item DOM node. + * @return {String} + */ + var getModelName = function(actionItem) { + return $(actionItem.closest('tr')[0]).find('span.target-name').text(); + }; + + /** @alias module:tool_analytics/model */ + return { + + /** + * Displays a confirm modal window before executing the action. + * + * @param {String} actionId + * @param {String} actionType + */ + confirmAction: function(actionId, actionType) { + $('[data-action-id="' + actionId + '"]').on('click', function(ev) { + ev.preventDefault(); + + var a = $(ev.currentTarget); + + if (typeof actionsList[actionType] === "undefined") { + log.error('Action "' + actionType + '" is not allowed.'); + return; + } + + var reqStrings = [ + actionsList[actionType].title, + actionsList[actionType].body + ]; + reqStrings[1].param = getModelName(a); + + var stringsPromise = Str.get_strings(reqStrings); + var modalPromise = ModalFactory.create({type: ModalFactory.types.SAVE_CANCEL}); + + $.when(stringsPromise, modalPromise).then(function(strings, modal) { + modal.setTitle(strings[0]); + modal.setBody(strings[1]); + modal.setSaveButtonText(strings[0]); + modal.getRoot().on(ModalEvents.save, function() { + window.location.href = a.attr('href'); + }); + modal.show(); + return modal; + }).fail(Notification.exception); + }); + } + }; +}); diff --git a/admin/tool/analytics/classes/output/models_list.php b/admin/tool/analytics/classes/output/models_list.php index b05e102099c8b..cc499ef534533 100644 --- a/admin/tool/analytics/classes/output/models_list.php +++ b/admin/tool/analytics/classes/output/models_list.php @@ -59,6 +59,7 @@ public function __construct($models) { * @return \stdClass */ public function export_for_template(\renderer_base $output) { + global $PAGE; $data = new \stdClass(); @@ -120,11 +121,13 @@ public function export_for_template(\renderer_base $output) { } } + // Has this model generated predictions?. + $predictioncontexts = $model->get_predictions_contexts(); + // Model predictions list. if (!$model->is_enabled()) { $modeldata->noinsights = get_string('disabledmodel', 'analytics'); } else if ($model->uses_insights()) { - $predictioncontexts = $model->get_predictions_contexts(); if ($predictioncontexts) { foreach ($predictioncontexts as $contextid => $unused) { @@ -166,9 +169,39 @@ public function export_for_template(\renderer_base $output) { $actionsmenu->set_owner_selector('model-actions-' . $model->get_id()); $actionsmenu->set_alignment(\action_menu::TL, \action_menu::BL); + $urlparams = ['id' => $model->get_id(), 'sesskey' => sesskey()]; + + // Get predictions. + if (!$onlycli && $modeldata->enabled && !empty($modeldata->timesplitting)) { + $urlparams['action'] = 'getpredictions'; + $url = new \moodle_url('model.php', $urlparams); + $icon = new \action_menu_link_secondary($url, new \pix_icon('i/notifications', + get_string('getpredictions', 'tool_analytics')), get_string('getpredictions', 'tool_analytics')); + $actionsmenu->add($icon); + } + + // Evaluate machine-learning-based models. + if (!$onlycli && $model->get_indicators() && !$model->is_static()) { + $urlparams['action'] = 'evaluate'; + $url = new \moodle_url('model.php', $urlparams); + $icon = new \action_menu_link_secondary($url, new \pix_icon('i/calc', get_string('evaluate', 'tool_analytics')), + get_string('evaluate', 'tool_analytics')); + $actionsmenu->add($icon); + } + + // Machine-learning-based models evaluation log. + if (!$model->is_static()) { + $urlparams['action'] = 'log'; + $url = new \moodle_url('model.php', $urlparams); + $icon = new \action_menu_link_secondary($url, new \pix_icon('i/report', get_string('viewlog', 'tool_analytics')), + get_string('viewlog', 'tool_analytics')); + $actionsmenu->add($icon); + } + // Edit model. if (!$model->is_static()) { - $url = new \moodle_url('model.php', array('action' => 'edit', 'id' => $model->get_id())); + $urlparams['action'] = 'edit'; + $url = new \moodle_url('model.php', $urlparams); $icon = new \action_menu_link_secondary($url, new \pix_icon('t/edit', get_string('edit')), get_string('edit')); $actionsmenu->add($icon); } @@ -183,42 +216,32 @@ public function export_for_template(\renderer_base $output) { $text = get_string('enable'); $icontype = 'i/checked'; } - $url = new \moodle_url('model.php', array('action' => $action, 'id' => $model->get_id())); + $urlparams['action'] = $action; + $url = new \moodle_url('model.php', $urlparams); $icon = new \action_menu_link_secondary($url, new \pix_icon($icontype, $text), $text); $actionsmenu->add($icon); - // Evaluate machine-learning-based models. - if (!$onlycli && $model->get_indicators() && !$model->is_static()) { - $url = new \moodle_url('model.php', array('action' => 'evaluate', 'id' => $model->get_id())); - $icon = new \action_menu_link_secondary($url, new \pix_icon('i/calc', get_string('evaluate', 'tool_analytics')), - get_string('evaluate', 'tool_analytics')); - $actionsmenu->add($icon); - } - - // Get predictions. - if (!$onlycli && $modeldata->enabled && !empty($modeldata->timesplitting)) { - $url = new \moodle_url('model.php', array('action' => 'getpredictions', 'id' => $model->get_id())); - $icon = new \action_menu_link_secondary($url, new \pix_icon('i/notifications', - get_string('getpredictions', 'tool_analytics')), get_string('getpredictions', 'tool_analytics')); - $actionsmenu->add($icon); - } - - // Machine-learning-based models evaluation log. - if (!$model->is_static()) { - $url = new \moodle_url('model.php', array('action' => 'log', 'id' => $model->get_id())); - $icon = new \action_menu_link_secondary($url, new \pix_icon('i/report', get_string('viewlog', 'tool_analytics')), - get_string('viewlog', 'tool_analytics')); - $actionsmenu->add($icon); - } - // Export training data. if (!$model->is_static() && $model->is_trained()) { - $url = new \moodle_url('model.php', array('action' => 'export', 'id' => $model->get_id())); + $urlparams['action'] = 'export'; + $url = new \moodle_url('model.php', $urlparams); $icon = new \action_menu_link_secondary($url, new \pix_icon('i/export', get_string('exporttrainingdata', 'tool_analytics')), get_string('export', 'tool_analytics')); $actionsmenu->add($icon); } + // Clear model. + if (!empty($predictioncontexts)) { + $actionid = 'clear-' . $model->get_id(); + $PAGE->requires->js_call_amd('tool_analytics/model', 'confirmAction', [$actionid, 'clear']); + $urlparams['action'] = 'clear'; + $url = new \moodle_url('model.php', $urlparams); + $icon = new \action_menu_link_secondary($url, new \pix_icon('e/cleanup_messy_code', + get_string('clearpredictions', 'tool_analytics')), get_string('clearpredictions', 'tool_analytics'), + ['data-action-id' => $actionid]); + $actionsmenu->add($icon); + } + $modeldata->actions = $actionsmenu->export_for_template($output); $data->models[] = $modeldata; diff --git a/admin/tool/analytics/lang/en/tool_analytics.php b/admin/tool/analytics/lang/en/tool_analytics.php index 3cdb7232e9e28..e1362fdca9710 100644 --- a/admin/tool/analytics/lang/en/tool_analytics.php +++ b/admin/tool/analytics/lang/en/tool_analytics.php @@ -29,6 +29,8 @@ $string['bettercli'] = 'Evaluating models and generating predictions may involve heavy processing. It is recommended to run these actions from the command line.'; $string['cantguessstartdate'] = 'Can\'t guess the start date'; $string['cantguessenddate'] = 'Can\'t guess the end date'; +$string['clearpredictions'] = 'Clear predictions'; +$string['clearmodelpredictions'] = 'Are you sure you want to clear all "{$a}" predictions?'; $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 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'; @@ -59,7 +61,6 @@ $string['insights'] = 'Insights'; $string['loginfo'] = 'Log extra info'; $string['modelresults'] = '{$a} results'; -$string['modelslist'] = 'Models list'; $string['modeltimesplitting'] = 'Time splitting'; $string['nodatatoevaluate'] = 'There is no data to evaluate the model'; $string['nodatatopredict'] = 'No new elements to get predictions for'; diff --git a/admin/tool/analytics/model.php b/admin/tool/analytics/model.php index 6d64c428c6750..e418b4656bb16 100644 --- a/admin/tool/analytics/model.php +++ b/admin/tool/analytics/model.php @@ -60,7 +60,9 @@ case 'export': $title = get_string('export', 'tool_analytics'); break; - + case 'clear': + $title = get_string('clearpredictions', 'tool_analytics'); + break; default: throw new moodle_exception('errorunknownaction', 'analytics'); } @@ -80,14 +82,21 @@ switch ($action) { case 'enable': + confirm_sesskey(); + $model->enable(); redirect(new \moodle_url('/admin/tool/analytics/index.php')); + break; case 'disable': + confirm_sesskey(); + $model->update(0, false, false); redirect(new \moodle_url('/admin/tool/analytics/index.php')); + break; case 'edit': + confirm_sesskey(); if ($model->is_static()) { echo $OUTPUT->header(); @@ -106,7 +115,6 @@ redirect(new \moodle_url('/admin/tool/analytics/index.php')); } else if ($data = $mform->get_data()) { - confirm_sesskey(); // Converting option names to class names. $indicators = array(); @@ -131,6 +139,8 @@ break; case 'evaluate': + confirm_sesskey(); + echo $OUTPUT->header(); if ($model->is_static()) { @@ -150,6 +160,8 @@ break; case 'getpredictions': + confirm_sesskey(); + echo $OUTPUT->header(); if ($onlycli) { @@ -200,6 +212,13 @@ $filename = 'training-data.' . $model->get_id() . '.' . time() . '.csv'; send_file($file, $filename, null, 0, false, true); break; + + case 'clear': + confirm_sesskey(); + + $model->clear(); + redirect(new \moodle_url('/admin/tool/analytics/index.php')); + break; } echo $OUTPUT->footer(); diff --git a/admin/tool/analytics/templates/models_list.mustache b/admin/tool/analytics/templates/models_list.mustache index 9330c5446d4d7..8eb6211a13814 100644 --- a/admin/tool/analytics/templates/models_list.mustache +++ b/admin/tool/analytics/templates/models_list.mustache @@ -111,7 +111,7 @@
- + @@ -126,7 +126,7 @@ {{#models}}
{{#str}}modelslist, tool_analytics{{/str}}{{#str}}analyticmodels, tool_analytics{{/str}}
{{#str}}target, tool_analytics{{/str}}
- {{target}} + {{target}} {{#targethelp}} {{>core/help_icon}} {{/targethelp}}