Skip to content

Commit 6fb28f1

Browse files
committed
MDL-70854 core: Add javascript & external service for stored progress bars.
- Adds javascript scripts - Adds external webservice to be called via ajax - Adds/alters mustache templates to render the bars
1 parent c7da06a commit 6fb28f1

File tree

8 files changed

+285
-21
lines changed

8 files changed

+285
-21
lines changed

lib/amd/build/stored_progress.min.js

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/amd/build/stored_progress.min.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/amd/src/stored_progress.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// This file is part of Moodle - http://moodle.org/
2+
//
3+
// Moodle is free software: you can redistribute it and/or modify
4+
// it under the terms of the GNU General Public License as published by
5+
// the Free Software Foundation, either version 3 of the License, or
6+
// (at your option) any later version.
7+
//
8+
// Moodle is distributed in the hope that it will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU General Public License for more details.
12+
//
13+
// You should have received a copy of the GNU General Public License
14+
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
15+
16+
/**
17+
* Script to update stored_progress progress bars on the screen.
18+
*
19+
* @copyright 2023 onwards Catalyst IT {@link http://www.catalyst-eu.net/}
20+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
21+
* @author Conn Warwicker <[email protected]>
22+
*/
23+
24+
/*global updateProgressBar*/
25+
26+
import * as Ajax from 'core/ajax';
27+
28+
/**
29+
* @var bool This AMD script is loaded multiple times, for each progress bar on a page.
30+
* So this stops it running multiple times.
31+
* */
32+
var STORED_PROGRESS_LOADED = false;
33+
34+
/**
35+
* Poll a given stored progress record.
36+
*
37+
* @param {array} ids
38+
* @param {integer} timeout
39+
*/
40+
function poll(ids, timeout) {
41+
42+
// Call AJAX request.
43+
let promise = Ajax.call([{
44+
methodname: 'core_poll_stored_progress', args: {'ids': ids}
45+
}]);
46+
47+
let repollids = [];
48+
49+
// When AJAX request returns, handle the results.
50+
promise[0].then(function(results) {
51+
52+
results.forEach(function(data) {
53+
54+
// Update the progress bar percentage and message using the core method from the javascript-static.js.
55+
updateProgressBar(data.uniqueid, data.progress, data.message, data.estimated, data.error);
56+
57+
// Add the bar for re-polling if it's not completed.
58+
if (data.progress < 100 && !data.error) {
59+
repollids.push(data.id);
60+
}
61+
62+
// If a different timeout came back from the script, use that instead.
63+
if (data.timeout && data.timeout > 0) {
64+
timeout = data.timeout;
65+
}
66+
67+
});
68+
69+
// If we still want to poll any of them, do it again.
70+
if (repollids.length > 0) {
71+
setTimeout(() => poll(repollids, timeout), timeout * 1000);
72+
}
73+
74+
}).catch(function() {
75+
// Do nothing.
76+
});
77+
78+
}
79+
80+
/**
81+
* Initialise the polling process.
82+
*
83+
* @param {integer} timeout Timeout to use (seconds).
84+
*/
85+
export const init = (timeout) => {
86+
87+
if (STORED_PROGRESS_LOADED === false) {
88+
89+
let ids = [];
90+
91+
// Find any stored progress bars we want to poll.
92+
document.querySelectorAll('.stored-progress-bar').forEach(el => {
93+
94+
// Get its id and add to array.
95+
let id = el.getAttribute('attr-id');
96+
ids.push(id);
97+
98+
});
99+
100+
// Poll for updates from these IDs.
101+
poll(ids, timeout);
102+
103+
// Script has run, we don't want it to run again.
104+
STORED_PROGRESS_LOADED = true;
105+
106+
}
107+
108+
};
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
// This file is part of Moodle - http://moodle.org/
3+
//
4+
// Moodle is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// Moodle is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16+
17+
namespace core\external;
18+
19+
use core_external\external_function_parameters;
20+
use core_external\external_multiple_structure;
21+
use core_external\external_single_structure;
22+
use core_external\external_value;
23+
24+
/**
25+
* Poll Stored Progress webservice.
26+
*
27+
* @package core
28+
* @copyright 2023 onwards Catalyst IT {@link http://www.catalyst-eu.net/}
29+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30+
* @author Conn Warwicker <[email protected]>
31+
*/
32+
class poll_stored_progress extends \core_external\external_api {
33+
34+
/**
35+
* Returns description of method parameters
36+
*
37+
* @return external_function_parameters
38+
*/
39+
public static function execute_parameters() {
40+
return new external_function_parameters([
41+
'ids' => new external_multiple_structure(
42+
new external_value(PARAM_INT, 'The stored_progress ID', VALUE_REQUIRED)
43+
),
44+
]);
45+
}
46+
47+
/**
48+
* Returns description of method return data
49+
*
50+
* @return external_multiple_structure
51+
*/
52+
public static function execute_returns() {
53+
return new external_multiple_structure(
54+
new external_single_structure([
55+
'id' => new external_value(PARAM_INT, 'stored_progress record id'),
56+
'uniqueid' => new external_value(PARAM_TEXT, 'unique element id'),
57+
'progress' => new external_value(PARAM_FLOAT, 'percentage progress'),
58+
'estimated' => new external_value(PARAM_RAW, 'estimated time left string'),
59+
'message' => new external_value(PARAM_TEXT, 'message to be displayed with the bar'),
60+
'error' => new external_value(PARAM_TEXT, 'error', VALUE_OPTIONAL),
61+
'timeout' => new external_value(PARAM_TEXT, 'timeout to use in the polling', VALUE_OPTIONAL),
62+
])
63+
);
64+
}
65+
66+
/**
67+
* Poll the database for the progress of stored progress objects
68+
*
69+
* @param array $ids
70+
* @return array
71+
*/
72+
public static function execute(array $ids) {
73+
global $CFG, $DB;
74+
75+
$params = self::validate_parameters(self::execute_parameters(), [
76+
'ids' => $ids,
77+
]);
78+
79+
$return = [];
80+
81+
foreach ($ids as $id) {
82+
83+
// Load the stored progress bar object.
84+
$bar = \core\stored_progress_bar::get_by_id($id);
85+
if ($bar) {
86+
87+
// Return the updated bar data.
88+
$return[$id] = [
89+
'id' => $id,
90+
'uniqueid' => $bar->get_id(),
91+
'progress' => $bar->get_percent(),
92+
'estimated' => $bar->get_estimate_message($bar->get_percent()),
93+
'message' => $bar->get_message(),
94+
'timeout' => \core\stored_progress_bar::get_timeout(),
95+
'error' => $bar->get_haserrored(),
96+
];
97+
98+
} else {
99+
100+
// If we could not find the record, we still need to return the right arguments in the array for the webservice.
101+
$return[$id] = [
102+
'id' => $id,
103+
'uniqueid' => '',
104+
'progress' => 0,
105+
'estimated' => '',
106+
'message' => get_string('invalidrecordunknown', 'error'),
107+
'timeout' => \core\stored_progress_bar::get_timeout(),
108+
'error' => true,
109+
];
110+
111+
}
112+
113+
}
114+
115+
return $return;
116+
}
117+
118+
}

lib/javascript-static.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,7 @@ function stripHTML(str) {
11641164
throw new Error('stripHTML can not be used any more. Please use jQuery instead.');
11651165
}
11661166

1167-
function updateProgressBar(id, percent, msg, estimate) {
1167+
function updateProgressBar(id, percent, msg, estimate, error) {
11681168
var event,
11691169
el = document.getElementById(id),
11701170
eventData = {};
@@ -1176,6 +1176,7 @@ function updateProgressBar(id, percent, msg, estimate) {
11761176
eventData.message = msg;
11771177
eventData.percent = percent;
11781178
eventData.estimate = estimate;
1179+
eventData.error = error;
11791180

11801181
try {
11811182
event = new CustomEvent('update', {

lib/outputrenderers.php

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5175,15 +5175,11 @@ public function render_progress_bar(progress_bar $bar) {
51755175
* @param float $percent
51765176
* @param string $msg Message
51775177
* @param string $estimate time remaining message
5178+
* @param bool $error
51785179
* @return string ascii fragment
51795180
*/
5180-
public function render_progress_bar_update(string $id, float $percent, string $msg, string $estimate): string {
5181-
return html_writer::script(js_writer::function_call('updateProgressBar', [
5182-
$id,
5183-
round($percent, 1),
5184-
$msg,
5185-
$estimate,
5186-
]));
5181+
public function render_progress_bar_update(string $id, float $percent, string $msg, string $estimate, bool $error = false): string {
5182+
return html_writer::script(js_writer::function_call('updateProgressBar', [$id, $percent, $msg, $estimate, $error]));
51875183
}
51885184

51895185
/**
@@ -5459,9 +5455,10 @@ public function render_progress_bar(progress_bar $bar) {
54595455
* @param float $percent
54605456
* @param string $msg Message
54615457
* @param string $estimate time remaining message
5458+
* @param bool $error
54625459
* @return string ascii fragment
54635460
*/
5464-
public function render_progress_bar_update(string $id, float $percent, string $msg, string $estimate): string {
5461+
public function render_progress_bar_update(string $id, float $percent, string $msg, string $estimate, bool $error = false): string {
54655462
$size = 55; // The width of the progress bar in chars.
54665463
$ascii = '';
54675464

lib/templates/progress_bar.mustache

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,39 +25,51 @@
2525
"width": "500"
2626
}
2727
}}
28-
<div id="{{id}}" class="progressbar_container mb-3">
28+
<div id="{{idnumber}}" class="progressbar_container mb-3 {{class}}" attr-id="{{id}}">
2929
<div class="progress">
30-
<div id="{{id}}_bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-value="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div>
30+
<div id="{{idnumber}}_bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-value="{{value}}" aria-valuemin="0" aria-valuemax="100" style="width: {{value}}%"></div>
3131
</div>
3232
<div class="d-flex">
3333
<div style="flex: 1 1 0; min-width: 0;">
34-
<div id="{{id}}_status" class="text-truncate">&nbsp;</div>
34+
<div id="{{idnumber}}_status" class="text-truncate">&nbsp;</div>
3535
</div>
3636
<div class="text-right pl-3" style="flex: 0 0 content">
37-
<span id="{{id}}_estimate" class="">&nbsp;</span>
38-
<span id="{{id}}_percentage" class="d-inline-block" style="width: 3em">0%</span>
37+
<span id="{{idnumber}}_estimate" class="">&nbsp;</span>
38+
<span id="{{idnumber}}_percentage" class="d-inline-block" style="width: 3em">{{value}}%</span>
3939
</div>
4040
</div>
4141
</div>
4242

4343
{{! We must not use the JS helper otherwise this gets executed too late. }}
4444
<script>
4545
(function() {
46-
var el = document.getElementById('{{id}}'),
47-
progressBar = document.getElementById('{{id}}_bar'),
48-
statusIndicator = document.getElementById('{{id}}_status'),
49-
estimateIndicator = document.getElementById('{{id}}_estimate');
50-
percentageIndicator = document.getElementById('{{id}}_percentage');
46+
47+
let el = document.getElementById('{{idnumber}}');
48+
let progressBar = document.getElementById('{{idnumber}}_bar');
49+
let statusIndicator = document.getElementById('{{idnumber}}_status');
50+
let estimateIndicator = document.getElementById('{{idnumber}}_estimate');
51+
let percentageIndicator = document.getElementById('{{idnumber}}_percentage');
52+
53+
// Change background colour to red if there was an error.
54+
if ({{error}} == 1) {
55+
el.querySelector('.progress-bar').style.background = 'red';
56+
}
5157
5258
el.addEventListener('update', function(e) {
5359
var msg = e.detail.message,
5460
percent = e.detail.percent,
55-
estimate = e.detail.estimate;
61+
estimate = e.detail.estimate
62+
error = e.detail.error;
5663
5764
statusIndicator.textContent = msg;
5865
progressBar.style.width = percent.toFixed(1) + '%';
5966
progressBar.setAttribute('value', percent.toFixed(1));
60-
if (percent === 100) {
67+
68+
if (error) {
69+
progressBar.classList.add('bg-danger');
70+
progressBar.classList.remove('bg-success');
71+
estimateIndicator.textContent = '';
72+
} else if (percent === 100) {
6173
progressBar.classList.add('bg-success');
6274
progressBar.classList.remove('progress-bar-striped');
6375
progressBar.classList.remove('progress-bar-animated');
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{{!
2+
This file is part of Moodle - http://moodle.org/
3+
4+
Moodle is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
Moodle is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16+
}}
17+
{{> core/progress_bar }}

0 commit comments

Comments
 (0)