mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 08:22:07 +02:00
MDL-81714 output: Update stored progress bar APIs
Expand the methods available in the stored_progress_bar output component and stored_progress_task_trait to allow a progress bar to be created in a "pending" state before the associated task is executed.
This commit is contained in:
parent
91e69cee7f
commit
b94b1ed5ff
@ -29,6 +29,9 @@ class stored_progress_bar extends progress_bar {
|
||||
/** @var bool Can use output buffering. */
|
||||
protected static $supportsoutputbuffering = true;
|
||||
|
||||
/** @var bool Flag to indicate the Javascript module has been initialised already. */
|
||||
protected static $jsloaded = false;
|
||||
|
||||
/** @var int DB record ID */
|
||||
protected $recordid;
|
||||
|
||||
@ -41,15 +44,19 @@ class stored_progress_bar extends progress_bar {
|
||||
/**
|
||||
* This overwrites the progress_bar::__construct method.
|
||||
*
|
||||
* The stored progress bar does not need to check NO_OUTPUT_BUFFERING since it outputs to the page
|
||||
* then polls for updates asynchronously, rather than waiting for synchronous updates in later output.
|
||||
*
|
||||
* @param string $idnumber
|
||||
* @param int $width The suggested width.
|
||||
* @param bool $autostart Whether to start the progress bar right away.
|
||||
*/
|
||||
public function __construct($idnumber) {
|
||||
public function __construct(string $idnumber, int $width = 0, bool $autostart = true) {
|
||||
|
||||
$this->clock = \core\di::get(\core\clock::class);
|
||||
|
||||
// Construct from the parent.
|
||||
parent::__construct($idnumber, 0, true);
|
||||
|
||||
parent::__construct($idnumber, $width, $autostart);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,10 +132,10 @@ class stored_progress_bar extends progress_bar {
|
||||
/**
|
||||
* Set the time we started the process.
|
||||
*
|
||||
* @param int $value
|
||||
* @param ?int $value
|
||||
* @return void
|
||||
*/
|
||||
protected function set_time_started(int $value): void {
|
||||
protected function set_time_started(?int $value): void {
|
||||
$this->timestart = $value;
|
||||
}
|
||||
|
||||
@ -185,17 +192,33 @@ class stored_progress_bar extends progress_bar {
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise Javascript for stored progress bars.
|
||||
*
|
||||
* The javascript polls the status of all progress bars on the page, so it only needs to be initialised once.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init_js(): void {
|
||||
global $PAGE;
|
||||
if (self::$jsloaded) {
|
||||
return;
|
||||
}
|
||||
$PAGE->requires->js_call_amd('core/stored_progress', 'init', [
|
||||
self::get_timeout(),
|
||||
]);
|
||||
self::$jsloaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content to display the progress bar and start polling via AJAX
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_content(): string {
|
||||
global $CFG, $PAGE, $OUTPUT;
|
||||
global $OUTPUT;
|
||||
|
||||
$PAGE->requires->js_call_amd('core/stored_progress', 'init', [
|
||||
self::get_timeout(),
|
||||
]);
|
||||
$this->init_js();
|
||||
|
||||
$context = $this->export_for_template($OUTPUT);
|
||||
return $OUTPUT->render_from_template('core/progress_bar', $context);
|
||||
@ -208,11 +231,15 @@ class stored_progress_bar extends progress_bar {
|
||||
* @return array
|
||||
*/
|
||||
public function export_for_template(\renderer_base $output): array {
|
||||
$class = 'stored-progress-bar';
|
||||
if (empty($this->timestart)) {
|
||||
$class .= ' stored-progress-notstarted';
|
||||
}
|
||||
return [
|
||||
'id' => $this->recordid,
|
||||
'idnumber' => $this->idnumber,
|
||||
'width' => $this->width,
|
||||
'class' => 'stored-progress-bar',
|
||||
'class' => $class,
|
||||
'value' => $this->percent,
|
||||
'message' => $this->message,
|
||||
'error' => $this->haserrored,
|
||||
@ -233,8 +260,19 @@ class stored_progress_bar extends progress_bar {
|
||||
$OUTPUT->render_progress_bar($this);
|
||||
}
|
||||
|
||||
// Delete any existing records for this.
|
||||
$this->clear_records();
|
||||
$record = $DB->get_record('stored_progress', ['idnumber' => $this->idnumber]);
|
||||
if ($record) {
|
||||
if ($record->timestart == 0) {
|
||||
// Set the timestart now and return.
|
||||
$record->timestart = $this->timestart;
|
||||
$DB->update_record('stored_progress', $record);
|
||||
$this->recordid = $record->id;
|
||||
return $this->recordid;
|
||||
} else {
|
||||
// Delete any existing records for this.
|
||||
$this->clear_records();
|
||||
}
|
||||
}
|
||||
|
||||
// Create new progress record.
|
||||
$this->recordid = $DB->insert_record('stored_progress', [
|
||||
@ -362,4 +400,25 @@ class stored_progress_bar extends progress_bar {
|
||||
return $CFG->progresspollinterval ?? 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a progress bar record in a pending state.
|
||||
*
|
||||
* @return int ID of the DB record
|
||||
*/
|
||||
public function store_pending(): int {
|
||||
global $DB;
|
||||
|
||||
// Delete any existing records for this.
|
||||
$this->clear_records();
|
||||
|
||||
// Create new progress record.
|
||||
$this->recordid = $DB->insert_record('stored_progress', [
|
||||
'idnumber' => $this->idnumber,
|
||||
'timestart' => $this->timestart,
|
||||
'message' => '',
|
||||
]);
|
||||
|
||||
return $this->recordid;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,10 @@
|
||||
|
||||
namespace core\task;
|
||||
|
||||
use core\progress\db_updater;
|
||||
use core\progress\stored;
|
||||
use core\output\stored_progress_bar;
|
||||
|
||||
/**
|
||||
* Trait to use in tasks to automatically add stored progress functionality.
|
||||
*
|
||||
@ -25,10 +29,44 @@ namespace core\task;
|
||||
* @author Conn Warwicker <conn.warwicker@catalyst-eu.net>
|
||||
*/
|
||||
trait stored_progress_task_trait {
|
||||
|
||||
/** @var \core\output\stored_progress_bar|null $progress */
|
||||
/** @var ?stored_progress_bar $progress */
|
||||
protected $progress = null;
|
||||
|
||||
/**
|
||||
* Construct a unique name for the progress bar.
|
||||
*
|
||||
* For adhoc tasks, this will need the ID in it. For scheduled tasks just the class name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_progress_name(): string {
|
||||
if (method_exists($this, 'get_id')) {
|
||||
return get_class($this) . '_' . $this->get_id();
|
||||
} else {
|
||||
return get_class($this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise a stored progress record.
|
||||
*/
|
||||
public function initialise_stored_progress(): void {
|
||||
$this->progress = new stored_progress_bar(
|
||||
stored_progress_bar::convert_to_idnumber($this->get_progress_name()),
|
||||
autostart: false,
|
||||
);
|
||||
$this->progress->store_pending();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a stored object for the stored progress record.
|
||||
*
|
||||
* @return stored
|
||||
*/
|
||||
public function get_progress(): stored {
|
||||
return new stored($this->progress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a stored progress bar implementation for the task this trait is used in.
|
||||
*
|
||||
@ -40,16 +78,8 @@ trait stored_progress_task_trait {
|
||||
// To get around the issue in MDL-80770, we are manually setting the renderer to cli.
|
||||
$OUTPUT = $PAGE->get_renderer('core', null, 'cli');
|
||||
|
||||
// Construct a unique name for the progress bar.
|
||||
// For adhoc tasks, this will need the ID in it. For scheduled tasks just the class name.
|
||||
if (method_exists($this, 'get_id')) {
|
||||
$name = get_class($this) . '_' . $this->get_id();
|
||||
} else {
|
||||
$name = get_class($this);
|
||||
}
|
||||
|
||||
$this->progress = new \core\output\stored_progress_bar(
|
||||
\core\output\stored_progress_bar::convert_to_idnumber($name)
|
||||
$this->progress = new stored_progress_bar(
|
||||
stored_progress_bar::convert_to_idnumber($this->get_progress_name())
|
||||
);
|
||||
|
||||
// Start the progress.
|
||||
|
@ -31,7 +31,7 @@
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div style="flex: 1 1 0; min-width: 0;">
|
||||
<div id="{{idnumber}}_status" class="text-truncate"> </div>
|
||||
<div id="{{idnumber}}_status" class="text-truncate">{{message}}</div>
|
||||
</div>
|
||||
<div class="text-end ps-3" style="flex: 0 0 content">
|
||||
<span id="{{idnumber}}_estimate" class=""> </span>
|
||||
|
Loading…
x
Reference in New Issue
Block a user