Skip to content

Commit a698eba

Browse files
committed
fix/improve listings of triggered courses in workflowoverview
1 parent d3b4db1 commit a698eba

File tree

10 files changed

+364
-170
lines changed

10 files changed

+364
-170
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
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+
/**
18+
* Table listing of all courses that are already in a process of the workflow.
19+
*
20+
* @package tool_lifecycle
21+
* @copyright 2025 Thomas Niedermaier Universität Münster
22+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23+
*/
24+
namespace tool_lifecycle\local\table;
25+
26+
use core_date;
27+
use stdClass;
28+
use tool_lifecycle\local\entity\workflow;
29+
use tool_lifecycle\local\manager\delayed_courses_manager;
30+
use tool_lifecycle\local\manager\lib_manager;
31+
use tool_lifecycle\local\manager\trigger_manager;
32+
use tool_lifecycle\local\manager\workflow_manager;
33+
use tool_lifecycle\local\response\trigger_response;
34+
use tool_lifecycle\urls;
35+
36+
defined('MOODLE_INTERNAL') || die;
37+
38+
require_once($CFG->libdir . '/tablelib.php');
39+
40+
/**
41+
* Table listing of all courses that are already in a process of the workflow.
42+
*
43+
* @package tool_lifecycle
44+
* @copyright 2025 Thomas Niedermaier Universität Münster
45+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46+
*/
47+
class courses_in_process_table extends \table_sql {
48+
49+
/** @var int $workflowid Id of the workflow */
50+
private $workflowid;
51+
52+
/** @var int $tablerows number of table rows effectively written */
53+
public $tablerows = 0;
54+
55+
/**
56+
* Builds a table of courses.
57+
* @param workflow $workflow of which the courses are listed
58+
* @param string $filterdata optional, term to filter the table by course id or -name
59+
* @throws \coding_exception
60+
* @throws \dml_exception
61+
*/
62+
public function __construct($workflow, $filterdata = '') {
63+
parent::__construct('tool_lifecycle-courses-in-process');
64+
global $PAGE;
65+
66+
$this->define_baseurl($PAGE->url);
67+
$this->workflowid = $workflow->id;
68+
69+
$a = new \stdClass();
70+
$a->title = $workflow->title;
71+
$this->caption = get_string('coursesinprocess', 'tool_lifecycle', $a);
72+
$this->captionattributes = ['class' => 'ml-3'];
73+
74+
$columns = ['courseid', 'coursefullname', 'coursecategory', 'processtype'];
75+
$this->define_columns($columns);
76+
$headers = [
77+
get_string('courseid', 'tool_lifecycle'),
78+
get_string('coursename', 'tool_lifecycle'),
79+
get_string('coursecategory', 'moodle'),
80+
get_string('step', 'tool_lifecycle')."/".get_string('error'),
81+
];
82+
$this->define_headers($headers);
83+
84+
$fields = " c.id as courseid,
85+
c.fullname as coursefullname,
86+
c.shortname as courseshortname,
87+
cc.name as coursecategory,
88+
pe.id as errorid,
89+
s.instancename as stepname";
90+
$from = " {course} c LEFT JOIN {course_categories} cc ON c.category = cc.id
91+
LEFT JOIN {tool_lifecycle_process} p ON c.id = p.courseid AND p.workflowid = $workflow->id
92+
LEFT JOIN {tool_lifecycle_proc_error} pe ON c.id = pe.courseid AND pe.workflowid = $workflow->id
93+
LEFT JOIN {tool_lifecycle_step} s ON p.stepindex = s.sortindex AND s.workflowid = $workflow->id
94+
";
95+
96+
$where = " p.workflowid IS NOT NULL OR pe.workflowid IS NOT NULL ";
97+
98+
if (!$workflow->includesitecourse) {
99+
$where = "($where) AND c.id <> 1 ";
100+
}
101+
102+
if ($filterdata) {
103+
if (is_numeric($filterdata)) {
104+
$where = "($where) AND c.id = $filterdata ";
105+
} else {
106+
$where = "($where) AND (c.fullname LIKE '%$filterdata%' OR c.shortname LIKE '%$filterdata%')";
107+
}
108+
}
109+
110+
$this->set_sql($fields, $from, $where, []);
111+
}
112+
113+
/**
114+
* Build the table from the fetched data.
115+
*
116+
* Take the data returned from the db_query and go through all the rows
117+
* processing each col using either col_{columnname} method or other_cols
118+
* method or if other_cols return NULL, then put the data straight into the
119+
* table.
120+
*
121+
* After calling this function, remember to call close_recordset.
122+
*/
123+
public function build_table() {
124+
if (!$this->rawdata) {
125+
return;
126+
}
127+
foreach ($this->rawdata as $row) {
128+
$formattedrow = $this->format_row($row);
129+
$this->add_data_keyed($formattedrow, $this->get_row_class($row));
130+
$this->tablerows++;
131+
}
132+
}
133+
134+
/**
135+
* Render coursefullname column.
136+
* @param object $row Row data.
137+
* @return string course link
138+
*/
139+
public function col_coursefullname($row) {
140+
$courselink = \html_writer::link(course_get_url($row->courseid),
141+
format_string($row->coursefullname), ['target' => '_blank']);
142+
return $courselink . '<br><span class="secondary-info">' . $row->courseshortname . '</span>';
143+
}
144+
145+
/**
146+
* Render processtype column.
147+
*
148+
* @param object $row Row data.
149+
* @return string of link to processerror-page or string 'step'
150+
* @throws \coding_exception
151+
* @throws \moodle_exception
152+
*/
153+
public function col_processtype($row) {
154+
if ($row->errorid) {
155+
$params = [
156+
'workflow' => $this->workflowid,
157+
'course' => $row->courseid,
158+
];
159+
return \html_writer::link(
160+
new \moodle_url(urls::PROCESS_ERRORS, $params),
161+
get_string('process_error', 'tool_lifecycle'),
162+
['class' => 'error']);
163+
} else {
164+
if ($row->stepname) {
165+
return $row->stepname;
166+
} else {
167+
return get_string('step', 'tool_lifecycle');
168+
}
169+
}
170+
}
171+
172+
/**
173+
* Hook that can be overridden in child classes to wrap a table in a form
174+
* for example. Called only when there is data to display and not
175+
* downloading.
176+
*/
177+
public function wrap_html_finish() {
178+
echo \html_writer::div(get_string('total')." ".get_string('page').": ".$this->tablerows." ".
179+
get_string('courses'), 'm-3');
180+
}
181+
182+
/**
183+
* Prints a customized "nothing to display" message.
184+
*/
185+
public function print_nothing_to_display() {
186+
global $OUTPUT;
187+
echo \html_writer::div($OUTPUT->notification(get_string('nothingtodisplay', 'moodle'), 'info'),
188+
'm-3');
189+
echo \html_writer::div("&nbsp;&nbsp;&nbsp;".\html_writer::link(new \moodle_url(urls::WORKFLOW_DETAILS,
190+
["wf" => $this->workflowid, "showsql" => "1", "showtablesql" => "1", "showdetails" => "1"]),
191+
"&nbsp;&nbsp;&nbsp;", ["class" => "text-muted fs-6 text-decoration-none"]));
192+
}
193+
}

classes/local/table/courses_in_step_table.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
namespace tool_lifecycle\local\table;
2626

27+
use core\output\single_button;
2728
use core_date;
2829
use tool_lifecycle\local\entity\step_subplugin;
2930
use tool_lifecycle\local\manager\settings_manager;
@@ -187,20 +188,26 @@ public function col_tools($row) {
187188
$rollback = settings_manager::get_settings($element->id, settings_type::STEP)['rollbackbuttonlabel'] ?? null;
188189
$proceed = settings_manager::get_settings($element->id, settings_type::STEP)['proceedbuttonlabel'] ?? null;
189190

190-
$output = $OUTPUT->single_button(
191+
$button = new \single_button(
191192
new \moodle_url($PAGE->url, ['action' => 'rollback', 'processid' => $row->processid,
192193
'sesskey' => sesskey(), 'search' => $this->search]),
193194
!empty($rollback) ? $rollback : get_string('rollback', 'lifecyclestep_adminapprove'),
194195
'post',
196+
single_button::BUTTON_SECONDARY,
195197
['class' => 'mr-1']
196198
);
197-
$output .= $OUTPUT->single_button(
199+
$output = $OUTPUT->render($button);
200+
201+
$button = new \single_button(
198202
new \moodle_url($PAGE->url, ['action' => 'proceed', 'processid' => $row->processid,
199203
'sesskey' => sesskey(), 'search' => $this->search]),
200204
!empty($proceed) ? $proceed : get_string('proceed', 'lifecyclestep_adminapprove'),
201205
'post',
206+
single_button::BUTTON_PRIMARY,
202207
['class' => 'mt-1']
203208
);
209+
$output .= $OUTPUT->render($button);
210+
204211
return $output;
205212
}
206213

classes/local/table/triggered_courses_table_trigger.php

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,24 @@ class triggered_courses_table_trigger extends \table_sql {
5959
/** @var int $triggerexclude if a trigger has setting exclude activated */
6060
private $triggerexclude;
6161

62-
/** @var int $otherwf to count the number of courses in another workflow */
62+
/** @var bool $coursecheckcode use course_check function to trigger courses */
63+
private $checkcoursecode = false;
64+
65+
/** @var int $otherwf to count the number of courses in another workflow on this page*/
6366
public $otherwf = 0;
6467

65-
/** @var int $delayed to count the number of courses that are delayed */
68+
/** @var int $delayed to count the number of courses that are delayed on this page */
6669
public $delayed = 0;
6770

68-
/** @var int $tablerows number of table rows effectively written */
71+
/** @var int $triggered to count the number of courses that are triggered on this page */
72+
public $triggered = 0;
73+
74+
/** @var int $tablerows number of table rows effectively written on this page */
6975
public $tablerows = 0;
7076

77+
/** @var int $excludedbycheckcourse number of courses excluded by function check_course on this page */
78+
public $excludedbycheckcourse = 0;
79+
7180
/**
7281
* Builds a table of courses.
7382
* @param trigger_subplugin $trigger of which the courses are listed
@@ -132,8 +141,7 @@ public function __construct($trigger, $type, $filterdata = '') {
132141
LEFT JOIN {tool_lifecycle_process} po ON c.id = po.courseid AND po.workflowid <> $workflow->id
133142
LEFT JOIN {tool_lifecycle_proc_error} peo ON c.id = peo.courseid AND peo.workflowid <> $workflow->id
134143
LEFT JOIN {tool_lifecycle_delayed} d ON c.id = d.courseid
135-
LEFT JOIN {tool_lifecycle_delayed_workf} dw ON c.id = dw.courseid
136-
AND dw.workflowid = $workflow->id ";
144+
LEFT JOIN {tool_lifecycle_delayed_workf} dw ON c.id = dw.courseid AND dw.workflowid=$workflow->id ";
137145

138146
$where .= " AND p.courseid IS NULL AND pe.courseid IS NULL ";
139147
if (!$workflow->includesitecourse) {
@@ -179,13 +187,8 @@ public function build_table() {
179187
$response = $lib->default_response();
180188
$course = new stdClass();
181189
foreach ($this->rawdata as $row) {
182-
if ($row->hasotherwfprocess) {
183-
$this->otherwf++;
184-
}
185-
if ($row->delaycourse && $row->delaycourse > time() && !$this->triggerexclude) {
186-
$this->delayed++;
187-
}
188190
if ($lib->check_course_code()) {
191+
$this->checkcoursecode = true;
189192
$course->id = $row->courseid;
190193
$response = $lib->check_course($course, $this->triggerid);
191194
}
@@ -226,22 +229,45 @@ public function col_coursefullname($row) {
226229
public function col_status($row) {
227230
$out = "";
228231
if ($row->hasotherwfprocess) {
232+
$this->otherwf++;
229233
$out .= \html_writer::div(get_string('alreadyinprocessotherworkflow', 'tool_lifecycle'),
230234
'text-warning');
231235
}
232236
if ($row->delaycourse && $row->delaycourse > time() && !$this->triggerexclude) {
237+
$this->delayed++;
233238
$out .= \html_writer::div(get_string('delayed', 'tool_lifecycle'), 'text-info');
234239
}
235240
if ($row->status && !($row->status == trigger_response::trigger())) {
241+
$this->excludedbycheckcourse++;
236242
$out .= \html_writer::div(get_string('excludedbycoursecode', 'tool_lifecycle'),
237243
'text-warning');
238244
}
239245
if ($out == "") {
246+
$this->triggered++;
240247
$out .= \html_writer::div(get_string('ok'), 'text-success');
241248
}
242249
return $out;
243250
}
244251

252+
/**
253+
* Hook that can be overridden in child classes to wrap a table in a form
254+
* for example. Called only when there is data to display and not
255+
* downloading.
256+
*/
257+
public function wrap_html_finish() {
258+
$a = new \stdClass();
259+
$a->otherwf = $this->otherwf;
260+
$a->delayed = $this->delayed;
261+
$a->triggered = $this->triggered;
262+
$a->tablerows = $this->tablerows;
263+
$cont = get_string('numbersotherwfordelayed', 'tool_lifecycle', $a);
264+
if ($this->checkcoursecode) {
265+
$cont .= " / ".$this->excludedbycheckcourse." ".
266+
get_string('excludedbycoursecode', 'tool_lifecycle');
267+
}
268+
echo \html_writer::div($cont, 'm-3');
269+
}
270+
245271
/**
246272
* Prints a customized "nothing to display" message.
247273
*/

0 commit comments

Comments
 (0)