Skip to content

Commit f742954

Browse files
Admin Dashboard is now configurable.
1 parent 7507acd commit f742954

17 files changed

+962
-204
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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+
* Dashboard box interface.
19+
*
20+
* @package theme_trema
21+
* @copyright 2025 TNG Consulting Inc. - {@link https://www.tngconsulting.ca/}
22+
* @author Michael Milette
23+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24+
*/
25+
26+
namespace theme_trema\dashboard;
27+
28+
/**
29+
* Interface for dashboard boxes.
30+
*
31+
* All dashboard boxes must implement this interface.
32+
*/
33+
interface box_interface {
34+
/**
35+
* Get the unique identifier for this box.
36+
*
37+
* @return string Box ID (e.g., 'diskusage', 'courses')
38+
*/
39+
public function get_id();
40+
41+
/**
42+
* Get the human-readable name of this box.
43+
*
44+
* @return string Box name for display in settings
45+
*/
46+
public function get_name();
47+
48+
/**
49+
* Get the template path for this box.
50+
*
51+
* @return string Template path (e.g., 'theme_trema/dashboard/boxes/dash-diskusage')
52+
*/
53+
public function get_template();
54+
55+
/**
56+
* Get the data to pass to the template.
57+
*
58+
* @return array Template context data
59+
*/
60+
public function get_data();
61+
62+
/**
63+
* Get the CSS class for this box.
64+
*
65+
* @return string CSS class name
66+
*/
67+
public function get_css_class();
68+
69+
/**
70+
* Check if this box requires JavaScript.
71+
*
72+
* @return string|false AMD module name or false if no JS needed
73+
*/
74+
public function requires_js();
75+
}

classes/dashboard/box_manager.php

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
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+
* Dashboard box manager.
19+
*
20+
* @package theme_trema
21+
* @copyright 2025 TNG Consulting Inc. - {@link https://www.tngconsulting.ca/}
22+
* @author Michael Milette
23+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24+
*/
25+
26+
namespace theme_trema\dashboard;
27+
28+
/**
29+
* Manager class for dashboard boxes.
30+
*/
31+
class box_manager {
32+
/**
33+
* Get all available box classes.
34+
*
35+
* @return array Array of box class names
36+
*/
37+
public static function get_available_boxes() {
38+
$boxdir = __DIR__ . '/boxes';
39+
$boxes = [];
40+
41+
if (is_dir($boxdir)) {
42+
$files = scandir($boxdir);
43+
foreach ($files as $file) {
44+
if (substr($file, 0, 5) === 'dash-' && substr($file, -4) === '.php') {
45+
// Extract box ID from filename (e.g., 'dash-diskusage.php' -> 'diskusage').
46+
$boxid = str_replace(['dash-', '.php'], '', $file);
47+
48+
// Build class name (e.g., 'theme_trema\dashboard\boxes\dash_diskusage').
49+
$classname = 'theme_trema\\dashboard\\boxes\\dash_' . $boxid;
50+
51+
// Try to instantiate the class.
52+
try {
53+
if (class_exists($classname)) {
54+
$box = new $classname();
55+
if ($box instanceof box_interface) {
56+
$boxes[$box->get_id()] = $box->get_name();
57+
}
58+
}
59+
} catch (\Exception $e) {
60+
// Skip boxes that fail to instantiate.
61+
debugging('Failed to load dashboard box: ' . $classname . ' - ' . $e->getMessage(), DEBUG_DEVELOPER);
62+
}
63+
}
64+
}
65+
}
66+
67+
return $boxes;
68+
}
69+
70+
/**
71+
* Get boxes for rendering.
72+
*
73+
* @param array $boxids Array of box IDs to render
74+
* @param \renderer_base $output Output renderer
75+
* @return array Array of box data for template
76+
*/
77+
public static function get_boxes_for_rendering($boxids, $output) {
78+
global $PAGE, $CFG;
79+
80+
$boxes = [];
81+
foreach ($boxids as $boxid) {
82+
if (empty($boxid) || $boxid === 'none') {
83+
continue;
84+
}
85+
86+
// Manually require the box file (autoloader may not work here).
87+
$filepath = $CFG->dirroot . '/theme/trema/classes/dashboard/boxes/dash-' . $boxid . '.php';
88+
if (file_exists($filepath)) {
89+
require_once($filepath);
90+
}
91+
92+
$classname = 'theme_trema\\dashboard\\boxes\\dash_' . $boxid;
93+
if (class_exists($classname)) {
94+
$box = new $classname();
95+
if ($box instanceof box_interface) {
96+
// Render box template.
97+
$content = $output->render_from_template($box->get_template(), $box->get_data());
98+
99+
// Load JS if needed.
100+
if ($jsmodule = $box->requires_js()) {
101+
$PAGE->requires->js_call_amd($jsmodule, 'init');
102+
}
103+
104+
$boxes[] = [
105+
'content' => $content,
106+
'cssclass' => $box->get_css_class(),
107+
];
108+
}
109+
}
110+
}
111+
112+
return $boxes;
113+
}
114+
115+
/**
116+
* Get column class based on number of boxes.
117+
*
118+
* @param int $count Number of boxes
119+
* @return string Bootstrap column class
120+
*/
121+
public static function get_column_class($count) {
122+
return match($count) {
123+
1 => 'col-12',
124+
2 => 'col-sm-6',
125+
3 => 'col-sm-4',
126+
4 => 'col-sm-3',
127+
default => 'col-sm-3'
128+
};
129+
}
130+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
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+
* Courses dashboard box.
19+
*
20+
* @package theme_trema
21+
* @copyright 2025 TNG Consulting Inc. - {@link https://www.tngconsulting.ca/}
22+
* @author Michael Milette
23+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24+
*/
25+
26+
namespace theme_trema\dashboard\boxes;
27+
28+
use theme_trema\dashboard\box_interface;
29+
30+
/**
31+
* Courses box class.
32+
*/
33+
class dash_courses implements box_interface {
34+
/**
35+
* Get box ID.
36+
*
37+
* @return string
38+
*/
39+
public function get_id() {
40+
return 'courses';
41+
}
42+
43+
/**
44+
* Get box name.
45+
*
46+
* @return string
47+
*/
48+
public function get_name() {
49+
return get_string('dashbox_courses', 'theme_trema');
50+
}
51+
52+
/**
53+
* Get template path.
54+
*
55+
* @return string
56+
*/
57+
public function get_template() {
58+
return 'theme_trema/dashboard/boxes/dash-courses';
59+
}
60+
61+
/**
62+
* Get box data.
63+
*
64+
* @return array
65+
*/
66+
public function get_data() {
67+
require_once(__DIR__ . '/../../../locallib.php');
68+
return [
69+
'activecourses' => $this->count_active_courses(),
70+
'totalcourses' => $this->count_courses(),
71+
];
72+
}
73+
74+
/**
75+
* Get CSS class.
76+
*
77+
* @return string
78+
*/
79+
public function get_css_class() {
80+
return 'dashboard-box-courses';
81+
}
82+
83+
/**
84+
* Check if requires JS.
85+
*
86+
* @return string|false
87+
*/
88+
public function requires_js() {
89+
return false;
90+
}
91+
92+
/**
93+
* Count active courses with status 1 and startdate less than today - Cached.
94+
*
95+
* @return int number of active courses
96+
*/
97+
private function count_active_courses() {
98+
global $DB;
99+
$cache = \cache::make('theme_trema', 'dashboardadmin');
100+
$activecourses = $cache->get('countactivecourses');
101+
if (!$activecourses) {
102+
$today = time();
103+
$sql = "SELECT COUNT(id) FROM {course}
104+
WHERE visible = 1 AND startdate <= :today AND (enddate > :today2 OR enddate = 0) AND format != 'site'";
105+
$activecourses = $DB->count_records_sql($sql, ['today' => $today, 'today2' => $today]);
106+
$cache->set('countactivecourses', $activecourses);
107+
}
108+
return $activecourses;
109+
}
110+
111+
/**
112+
* Count all courses - Cached.
113+
*
114+
* @return int number of all courses
115+
*/
116+
private function count_courses() {
117+
global $DB;
118+
$cache = \cache::make('theme_trema', 'dashboardadmin');
119+
$courses = $cache->get('courses');
120+
if (!$courses) {
121+
$courses = $DB->count_records('course') - 1; // Delete course site.
122+
$cache->set('courses', $courses);
123+
}
124+
return $courses;
125+
}
126+
}

0 commit comments

Comments
 (0)