MDL-81714 grades: Display "Run now" button for admins in task indicator
This commit is contained in:
@@ -6,7 +6,7 @@ date: 2024-08-21T00:00:00+01:00
|
||||
draft: false
|
||||
tags:
|
||||
- MDL-81714
|
||||
- 4.5
|
||||
- 5.0
|
||||
---
|
||||
|
||||
{{< mustache template="core/task_indicator" >}}
|
||||
@@ -89,5 +89,34 @@ if ($taskindicator->has_task_record()) {
|
||||
|
||||
{{< /php >}}
|
||||
|
||||
When the task begins running and the progress is updated, the progress bar will automatically be displayed.
|
||||
|
||||
If the optional `redirecturl` parameter is set when creating the indicator, the page will automatically reload or redirect to
|
||||
this URL when the progress bar completes.
|
||||
|
||||
While the task is still queued, admins will see a "Run now" button below the indicator. This is designed for convenience if
|
||||
a user is blocked on a job and needs the task run immediately. It will run the specific instance of the task tracked by the
|
||||
indicator.
|
||||
|
||||
{{< mustache template="core/task_indicator" >}}
|
||||
{
|
||||
"heading": "Regrade in progress",
|
||||
"icon": {
|
||||
"attributes": [
|
||||
{"name": "src", "value": "/pix/i/timer.svg"},
|
||||
{"name": "alt", "value": ""}
|
||||
]
|
||||
},
|
||||
"message": "Grades are being recalculated due to recent changes.",
|
||||
"progress": {
|
||||
"id": "progressbar_test",
|
||||
"message": "Task pending",
|
||||
"idnumber": "progressbar_test",
|
||||
"class": "stored-progress-bar stored-progress-notstarted",
|
||||
"width": "500",
|
||||
"value": "0"
|
||||
},
|
||||
"runurl": "http://example.com/runtask.php?id=1",
|
||||
"runlabel": "Run now"
|
||||
}
|
||||
{{< /mustache >}}
|
||||
|
||||
@@ -54,15 +54,14 @@ Feature: Asynchronous regrade on a large course
|
||||
And I set the field "Maximum grade" to "50"
|
||||
And I press "Save and return to course"
|
||||
And I log out
|
||||
And I change the viewport size to "medium"
|
||||
|
||||
Scenario Outline: Task indicator displays on all grade reports when a calculation is pending
|
||||
Given I am on the "Test course 2" "<report>" page logged in as "<user>"
|
||||
Then I should not see "Grades are being recalculated due to recent changes."
|
||||
Then I should not see "The report will update automatically. You don't need to do anything."
|
||||
And <element> should exist
|
||||
When I am on the "Test course 1" "<report>" page logged in as "<user>"
|
||||
Then I should see "Grades are being recalculated due to recent changes."
|
||||
And I should see "Task pending"
|
||||
And I should see "0.0%"
|
||||
Then I should see "The report will update automatically. You don't need to do anything."
|
||||
And <element> should not exist
|
||||
|
||||
Examples:
|
||||
@@ -77,10 +76,10 @@ Feature: Asynchronous regrade on a large course
|
||||
Scenario Outline: Gradebook settings can be accessed when a regrade is pending
|
||||
Given I am on the "Test course 2" "<page>" page logged in as "teacher1"
|
||||
Then I should see "<text>"
|
||||
And I should not see "Grades are being recalculated due to recent changes."
|
||||
And I should not see "The report will update automatically. You don't need to do anything."
|
||||
Given I am on the "Test course 1" "<page>" page logged in as "teacher1"
|
||||
Then I should see "<text>"
|
||||
And I should not see "Grades are being recalculated due to recent changes."
|
||||
And I should not see "The report will update automatically. You don't need to do anything."
|
||||
|
||||
Examples:
|
||||
| page | text |
|
||||
@@ -92,36 +91,32 @@ Feature: Asynchronous regrade on a large course
|
||||
When I follow "Grades" in the user menu
|
||||
And I follow "Test course 2"
|
||||
Then "table.user-grade" "css_element" should exist
|
||||
Then I should not see "Grades are being recalculated due to recent changes."
|
||||
Then I should not see "The report will update automatically. You don't need to do anything."
|
||||
When I follow "Grades" in the user menu
|
||||
And I follow "Test course 1"
|
||||
Then "table.user-grade" "css_element" should not exist
|
||||
Then I should see "Grades are being recalculated due to recent changes."
|
||||
Then I should see "The report will update automatically. You don't need to do anything."
|
||||
|
||||
Scenario: Task indicator progresses and redirects when the task is run.
|
||||
When I am on the "Test course 1" "grades > Grader report > View" page logged in as teacher1
|
||||
And I should see "Grades are being recalculated due to recent changes."
|
||||
And I should see "Task pending"
|
||||
And I should see "0.0%"
|
||||
And I should see "The report will update automatically. You don't need to do anything."
|
||||
And I should not see "Run now"
|
||||
And I should not see "0.0%"
|
||||
And "user-grades" "table" should not exist
|
||||
When I run all adhoc tasks
|
||||
And I run all adhoc tasks
|
||||
# Progress bar should update.
|
||||
# Manual wait is a bit of a fudge, but we need the progress bar to poll for an update.
|
||||
And I wait "1" seconds
|
||||
Then I should not see "Task pending"
|
||||
And I should see "Recalculating grades"
|
||||
And I wait until "Recalculating grades" "text" exists
|
||||
And I should see "100%"
|
||||
When I wait "2" seconds
|
||||
# The page should reload after a short delay.
|
||||
Then I should not see "Grades are being recalculated due to recent changes."
|
||||
Then I wait until "Recalculating grades" "text" does not exist
|
||||
And I set the field "Search users" to "Student 1"
|
||||
And "user-grades" "table" should exist
|
||||
And "40.00" "text" should exist in the "student1@example.com" "table_row"
|
||||
|
||||
Scenario: Admin should see a "Run now" button in the task indicator
|
||||
When I am on the "Test course 1" "grades > Grader report > View" page logged in as admin
|
||||
And I should see "Grades are being recalculated due to recent changes."
|
||||
And I should see "Task pending"
|
||||
And I should see "The report will update automatically. You don't need to do anything."
|
||||
And I should not see "0.0%"
|
||||
And I should see "Run now"
|
||||
|
||||
Scenario: Making changes on course with less than 100 grades performs the regrade synchronously, no indicator is shown.
|
||||
@@ -131,17 +126,17 @@ Feature: Asynchronous regrade on a large course
|
||||
And I set the field "Maximum grade" to "50"
|
||||
And I press "Save and return to course"
|
||||
When I am on the "Test course 2" "grades > Grader report > View" page
|
||||
Then I should not see "Grades are being recalculated due to recent changes."
|
||||
Then I should not see "The report will update automatically. You don't need to do anything."
|
||||
And "user-grades" "table" should exist
|
||||
|
||||
Scenario: Editing weights triggers a regrade, but further edits are possible
|
||||
Given I run all adhoc tasks
|
||||
And I am on the "Test course 1" "grades > Grader report > View" page logged in as "teacher1"
|
||||
And I should not see "Grades are being recalculated due to recent changes."
|
||||
And I should not see "The report will update automatically. You don't need to do anything."
|
||||
And I am on the "Test course 1" "grades > Gradebook setup" page
|
||||
When I set the field "Override weight of Test assignment 1" to "1"
|
||||
And I press "Save changes"
|
||||
And I am on the "Test course 1" "grades > Grader report > View" page
|
||||
And I should see "Grades are being recalculated due to recent changes."
|
||||
And I should see "The report will update automatically. You don't need to do anything."
|
||||
And I am on the "Test course 1" "grades > Gradebook setup" page
|
||||
And I should not see "Grades are being recalculated due to recent changes."
|
||||
And I should not see "The report will update automatically. You don't need to do anything."
|
||||
|
||||
Vendored
+1
-1
@@ -9,6 +9,6 @@ define("core/task_indicator",["exports"],(function(_exports){Object.defineProper
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class{static init(id,redirectUrl){document.getElementById(id).addEventListener("update",(event=>{100===event.detail.percent&&window.setTimeout((()=>window.location.assign(redirectUrl)),2e3)}))}},_exports.default}));
|
||||
class{static init(id,redirectUrl){const bar=document.getElementById(id);bar.addEventListener("update",(event=>{var _event$detail;const percent=null==event||null===(_event$detail=event.detail)||void 0===_event$detail?void 0:_event$detail.percent;if(percent>0){bar.classList.remove("stored-progress-notstarted");const runlink=document.querySelector(".runlink[data-idnumber=".concat(id,"]"));runlink&&runlink.remove()}""!==redirectUrl&&100===percent&&window.setTimeout((()=>window.location.assign(redirectUrl)),2e3)}))}},_exports.default}));
|
||||
|
||||
//# sourceMappingURL=task_indicator.min.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"task_indicator.min.js","sources":["../src/task_indicator.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Task indicator\n *\n * Watches the progress bar inside the task indicator for updates, and redirects when the progress is complete.\n *\n * @module core/task_indicator\n * @copyright 2024 Catalyst IT Europe Ltd\n * @author Mark Johnson <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default class {\n /**\n * Watch the progress bar for updates.\n *\n * When the progress bar is updated to 100%, wait a couple of seconds so the user gets to see it if they are watching,\n * then redirect to the specified URL.\n *\n * @param {String} id\n * @param {String} redirectUrl\n */\n static init(id, redirectUrl) {\n document.getElementById(id).addEventListener('update', (event) => {\n if (event.detail.percent === 100) {\n window.setTimeout(() => window.location.assign(redirectUrl), 2000);\n }\n });\n }\n}\n"],"names":["id","redirectUrl","document","getElementById","addEventListener","event","detail","percent","window","setTimeout","location","assign"],"mappings":";;;;;;;;;;;kBAmCgBA,GAAIC,aACZC,SAASC,eAAeH,IAAII,iBAAiB,UAAWC,QACvB,MAAzBA,MAAMC,OAAOC,SACbC,OAAOC,YAAW,IAAMD,OAAOE,SAASC,OAAOV,cAAc"}
|
||||
{"version":3,"file":"task_indicator.min.js","sources":["../src/task_indicator.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Task indicator\n *\n * Watches the progress bar inside the task indicator for updates, and redirects when the progress is complete.\n *\n * @module core/task_indicator\n * @copyright 2024 Catalyst IT Europe Ltd\n * @author Mark Johnson <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default class {\n /**\n * Watch the progress bar for updates.\n *\n * When the progress bar is updated to 100%, wait a couple of seconds so the user gets to see it if they are watching,\n * then redirect to the specified URL.\n *\n * @param {String} id The ID of the progress bar element.\n * @param {String} redirectUrl Optional URL to redirect to once the task is complete.\n */\n static init(id, redirectUrl) {\n const bar = document.getElementById(id);\n bar.addEventListener('update', (event) => {\n const percent = event?.detail?.percent;\n if (percent > 0) {\n // Once progress starts, display the progress bar and remove the run link.\n bar.classList.remove('stored-progress-notstarted');\n const runlink = document.querySelector(`.runlink[data-idnumber=${id}]`);\n if (runlink) {\n runlink.remove();\n }\n }\n // Once the progress bar completes, redirect the page.\n if (redirectUrl !== '' && percent === 100) {\n window.setTimeout(() => window.location.assign(redirectUrl), 2000);\n }\n });\n }\n}\n"],"names":["id","redirectUrl","bar","document","getElementById","addEventListener","event","percent","detail","_event$detail","classList","remove","runlink","querySelector","window","setTimeout","location","assign"],"mappings":";;;;;;;;;;;kBAmCgBA,GAAIC,mBACNC,IAAMC,SAASC,eAAeJ,IACpCE,IAAIG,iBAAiB,UAAWC,gCACtBC,QAAUD,MAAAA,6BAAAA,MAAOE,uCAAPC,cAAeF,WAC3BA,QAAU,EAAG,CAEbL,IAAIQ,UAAUC,OAAO,oCACfC,QAAUT,SAASU,+CAAwCb,SAC7DY,SACAA,QAAQD,SAII,KAAhBV,aAAkC,MAAZM,SACtBO,OAAOC,YAAW,IAAMD,OAAOE,SAASC,OAAOhB,cAAc"}
|
||||
@@ -30,12 +30,23 @@ export default class {
|
||||
* When the progress bar is updated to 100%, wait a couple of seconds so the user gets to see it if they are watching,
|
||||
* then redirect to the specified URL.
|
||||
*
|
||||
* @param {String} id
|
||||
* @param {String} redirectUrl
|
||||
* @param {String} id The ID of the progress bar element.
|
||||
* @param {String} redirectUrl Optional URL to redirect to once the task is complete.
|
||||
*/
|
||||
static init(id, redirectUrl) {
|
||||
document.getElementById(id).addEventListener('update', (event) => {
|
||||
if (event.detail.percent === 100) {
|
||||
const bar = document.getElementById(id);
|
||||
bar.addEventListener('update', (event) => {
|
||||
const percent = event?.detail?.percent;
|
||||
if (percent > 0) {
|
||||
// Once progress starts, display the progress bar and remove the run link.
|
||||
bar.classList.remove('stored-progress-notstarted');
|
||||
const runlink = document.querySelector(`.runlink[data-idnumber=${id}]`);
|
||||
if (runlink) {
|
||||
runlink.remove();
|
||||
}
|
||||
}
|
||||
// Once the progress bar completes, redirect the page.
|
||||
if (redirectUrl !== '' && percent === 100) {
|
||||
window.setTimeout(() => window.location.assign(redirectUrl), 2000);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -16,14 +16,21 @@
|
||||
|
||||
namespace core\output;
|
||||
|
||||
use core\plugin_manager;
|
||||
use core\task\adhoc_task;
|
||||
use core\task\stored_progress_task_trait;
|
||||
use core\url;
|
||||
use core\context\system;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Indicator for displaying status and progress of a background task
|
||||
*
|
||||
* This will display a section containing an icon, heading and message describing the background task being performed,
|
||||
* as well as a progress bar that is updated as the task progresses. Optionally, it will redirect to a given URL (or reload
|
||||
* the current one) when the task completes. If the task is still waiting in the queue, an admin viewing the indicator
|
||||
* will also see a "Run now" button.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2024 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <[email protected]>
|
||||
@@ -36,6 +43,12 @@ class task_indicator implements renderable, templatable {
|
||||
/** @var ?stored_progress_bar $progressbar */
|
||||
protected ?stored_progress_bar $progressbar;
|
||||
|
||||
/** @var ?url $runurl The URL to manually run the task. */
|
||||
protected ?url $runurl = null;
|
||||
|
||||
/** @var string $runlabel Label for the link to run the task. */
|
||||
protected string $runlabel = '';
|
||||
|
||||
/**
|
||||
* Find the task record, and get the progress bar object.
|
||||
*
|
||||
@@ -80,6 +93,16 @@ class task_indicator implements renderable, templatable {
|
||||
$this->task->set_id($this->taskrecord->id);
|
||||
$idnumber = stored_progress_bar::convert_to_idnumber($this->task::class, $this->task->get_id());
|
||||
$this->progressbar = stored_progress_bar::get_by_idnumber($idnumber);
|
||||
// As long as the tool_task plugin hasn't been removed,
|
||||
// allow admins to trigger the task manually if it's not running yet.
|
||||
if (
|
||||
array_key_exists('task', plugin_manager::instance()->get_present_plugins('tool'))
|
||||
&& is_null($this->taskrecord->timestarted)
|
||||
&& has_capability('moodle/site:config', system::instance())
|
||||
) {
|
||||
$this->runurl = new url('/admin/tool/task/run_adhoctasks.php', ['id' => $this->taskrecord->id]);
|
||||
$this->runlabel = get_string('runnow', 'tool_task');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,8 +126,10 @@ class task_indicator implements renderable, templatable {
|
||||
$export['message'] = $this->message;
|
||||
$export['progress'] = $this->progressbar->export_for_template($output);
|
||||
$export['icon'] = $this->icon ? $this->icon->export_for_template($output) : '';
|
||||
$export['redirecturl'] = $this->redirecturl->out();
|
||||
$export['redirecturl'] = $this->redirecturl?->out();
|
||||
$export['extraclasses'] = implode(' ', $this->extraclasses);
|
||||
$export['runurl'] = $this->runurl?->out();
|
||||
$export['runlabel'] = $this->runlabel;
|
||||
$this->progressbar->init_js();
|
||||
}
|
||||
return $export;
|
||||
|
||||
@@ -33,29 +33,36 @@
|
||||
"id": "progressbar_test",
|
||||
"message": "Recalculating grades",
|
||||
"idnumber": "progressbar_test",
|
||||
"class": "stored-progress-bar",
|
||||
"width": "500",
|
||||
"value": "50"
|
||||
}
|
||||
}
|
||||
}}
|
||||
<div class="task-indicator {{extraclasses}}">
|
||||
{{#icon}}
|
||||
<div class="text-center">
|
||||
{{>core/pix_icon}}
|
||||
</div>
|
||||
{{/icon}}
|
||||
<h3 class="text-center">{{heading}}</h3>
|
||||
<p class="text-center">{{message}}</p>
|
||||
<div class="text-center">
|
||||
{{#icon}}
|
||||
<div>
|
||||
{{>core/pix_icon}}
|
||||
</div>
|
||||
{{/icon}}
|
||||
<h2>{{heading}}</h2>
|
||||
<p>{{message}}</p>
|
||||
</div>
|
||||
{{#runurl}}
|
||||
<p class="text-center">
|
||||
<a class="runlink btn btn-primary" href="{{runurl}}" data-idnumber="{{progress.idnumber}}">{{runlabel}}</a>
|
||||
</p>
|
||||
{{/runurl}}
|
||||
{{#progress}}
|
||||
{{>core/progress_bar}}
|
||||
{{/progress}}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{{#redirecturl}}
|
||||
{{#js}}
|
||||
require(['core/task_indicator'], function(TaskIndicator) {
|
||||
TaskIndicator.init('{{progress.idnumber}}', '{{redirecturl}}');
|
||||
});
|
||||
{{/js}}
|
||||
{{/redirecturl}}
|
||||
|
||||
{{#js}}
|
||||
require(['core/task_indicator'], function(TaskIndicator) {
|
||||
TaskIndicator.init('{{progress.idnumber}}', '{{redirecturl}}');
|
||||
});
|
||||
{{/js}}
|
||||
|
||||
Reference in New Issue
Block a user