mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 16:32:18 +02:00
MDL-52828 competencies: Filter by activity
On the competency breakdown report, allow filter by competencies linked to an activity.
This commit is contained in:
parent
9d4f4f0051
commit
27737ae666
@ -107,6 +107,7 @@ $string['editthisuserevidence'] = 'Edit this evidence';
|
||||
$string['edituserevidence'] = 'Edit evidence';
|
||||
$string['evidence'] = 'Evidence';
|
||||
$string['findcourses'] = 'Find courses';
|
||||
$string['filterbyactivity'] = 'Filter competencies by resource or activity';
|
||||
$string['frameworkcannotbedeleted'] = 'The competency framework \'{$a}\' cannot be deleted';
|
||||
$string['hidden'] = 'Hidden';
|
||||
$string['hiddenhint'] = '(hidden)';
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
// No example context because the JS is connected to webservices
|
||||
}}
|
||||
<div class="float-sm-right card card-block">
|
||||
<div class="float-sm-right card card-block p-x-1 p-b-1">
|
||||
<p>{{{groupselector}}}</p>
|
||||
<form class="user-competency-course-navigation">
|
||||
{{#hasusers}}
|
||||
|
@ -1 +1 @@
|
||||
define(["jquery","core/notification","core/str","core/ajax","core/log","core/templates","tool_lp/dialogue"],function(a,b,c,d,e,f,g){var h=function(b,c){this._regionSelector=b,this._userCompetencySelector=c,a(this._regionSelector).on("click",this._userCompetencySelector,this._handleClick.bind(this))};return h.prototype._handleClick=function(c){var f=a(c.target).closest(this._userCompetencySelector),g=a(f).data("competencyid"),h=a(f).data("courseid"),i=a(f).data("userid");e.debug("Clicked on cell: competencyId="+g+", courseId="+h+", userId="+i);var j=d.call([{methodname:"tool_lp_data_for_user_competency_summary_in_course",args:{userid:i,competencyid:g,courseid:h}},{methodname:"core_competency_user_competency_viewed_in_course",args:{userid:i,competencyid:g,courseid:h}}]);a.when.apply(a,j).then(function(a){this._contextLoaded.bind(this)(a)}.bind(this))["catch"](b.exception)},h.prototype._contextLoaded=function(a){var d=this;a.displayuser=!0,f.render("tool_lp/user_competency_summary_in_course",a).done(function(a,e){c.get_string("usercompetencysummary","report_competency").done(function(b){new g(b,a,f.runTemplateJS.bind(f,e),d._refresh.bind(d),(!0))}).fail(b.exception)}).fail(b.exception)},h.prototype._refresh=function(){var c=a(this._regionSelector),e=c.data("courseid"),f=c.data("userid");d.call([{methodname:"report_competency_data_for_report",args:{courseid:e,userid:f},done:this._pageContextLoaded.bind(this),fail:b.exception}])},h.prototype._pageContextLoaded=function(a){var c=this;f.render("report_competency/report",a).done(function(a,b){f.replaceNode(c._regionSelector,a,b)}).fail(b.exception)},h.prototype._regionSelector=null,h.prototype._userCompetencySelector=null,h});
|
||||
define(["jquery","core/notification","core/str","core/ajax","core/log","core/templates","tool_lp/dialogue"],function(a,b,c,d,e,f,g){var h=function(b,c){this._regionSelector=b,this._userCompetencySelector=c,a(this._regionSelector).on("click",this._userCompetencySelector,this._handleClick.bind(this))};return h.prototype._handleClick=function(c){var f=a(c.target).closest(this._userCompetencySelector),g=a(f).data("competencyid"),h=a(f).data("courseid"),i=a(f).data("userid");e.debug("Clicked on cell: competencyId="+g+", courseId="+h+", userId="+i);var j=d.call([{methodname:"tool_lp_data_for_user_competency_summary_in_course",args:{userid:i,competencyid:g,courseid:h}},{methodname:"core_competency_user_competency_viewed_in_course",args:{userid:i,competencyid:g,courseid:h}}]);a.when.apply(a,j).then(function(a){this._contextLoaded.bind(this)(a)}.bind(this))["catch"](b.exception)},h.prototype._contextLoaded=function(a){var d=this;a.displayuser=!0,f.render("tool_lp/user_competency_summary_in_course",a).done(function(a,e){c.get_string("usercompetencysummary","report_competency").done(function(b){new g(b,a,f.runTemplateJS.bind(f,e),d._refresh.bind(d),(!0))}).fail(b.exception)}).fail(b.exception)},h.prototype._refresh=function(){var c=a(this._regionSelector),e=c.data("courseid"),f=c.data("moduleid"),g=c.data("userid");d.call([{methodname:"report_competency_data_for_report",args:{courseid:e,userid:g,moduleid:f},done:this._pageContextLoaded.bind(this),fail:b.exception}])},h.prototype._pageContextLoaded=function(a){var c=this;f.render("report_competency/report",a).done(function(a,b){f.replaceNode(c._regionSelector,a,b)}).fail(b.exception)},h.prototype._regionSelector=null,h.prototype._userCompetencySelector=null,h});
|
@ -1 +1 @@
|
||||
define(["jquery"],function(a){var b=function(b,c,d,e){this._baseUrl=c,this._userId=d+"",this._courseId=e,a(b).on("change",this._userChanged.bind(this))};return b.prototype._userChanged=function(b){var c=a(b.target).val(),d="?user="+c+"&id="+this._courseId;document.location=this._baseUrl+d},b.prototype._userId=null,b.prototype._courseId=null,b.prototype._baseUrl=null,b});
|
||||
define(["jquery"],function(a){var b=function(b,c,d,e,f,g){this._baseUrl=d,this._userId=e+"",this._courseId=f,this._moduleId=g,a(b).on("change",this._userChanged.bind(this)),a(c).on("change",this._moduleChanged.bind(this))};return b.prototype._userChanged=function(b){var c=a(b.target).val(),d="?user="+c+"&id="+this._courseId+"&mod="+this._moduleId;document.location=this._baseUrl+d},b.prototype._moduleChanged=function(b){var c=a(b.target).val(),d="?mod="+c+"&id="+this._courseId+"&user="+this._userId;document.location=this._baseUrl+d},b.prototype._userId=null,b.prototype._moduleId=null,b.prototype._courseId=null,b.prototype._baseUrl=null,b});
|
@ -90,11 +90,12 @@ define(['jquery', 'core/notification', 'core/str', 'core/ajax', 'core/log', 'cor
|
||||
GradingPopup.prototype._refresh = function() {
|
||||
var region = $(this._regionSelector);
|
||||
var courseId = region.data('courseid');
|
||||
var moduleId = region.data('moduleid');
|
||||
var userId = region.data('userid');
|
||||
|
||||
ajax.call([{
|
||||
methodname: 'report_competency_data_for_report',
|
||||
args: {courseid: courseId, userid: userId},
|
||||
args: {courseid: courseId, userid: userId, moduleid: moduleId},
|
||||
done: this._pageContextLoaded.bind(this),
|
||||
fail: notification.exception
|
||||
}]);
|
||||
|
@ -27,16 +27,20 @@ define(['jquery'], function($) {
|
||||
* UserCourseNavigation
|
||||
*
|
||||
* @param {String} userSelector The selector of the user element.
|
||||
* @param {String} moduleSelector The selector of the module element.
|
||||
* @param {String} baseUrl The base url for the page (no params).
|
||||
* @param {Number} userId The course id
|
||||
* @param {Number} courseId The user id
|
||||
* @param {Number} moduleId The activity module (filter)
|
||||
*/
|
||||
var UserCourseNavigation = function(userSelector, baseUrl, userId, courseId) {
|
||||
var UserCourseNavigation = function(userSelector, moduleSelector, baseUrl, userId, courseId, moduleId) {
|
||||
this._baseUrl = baseUrl;
|
||||
this._userId = userId + '';
|
||||
this._courseId = courseId;
|
||||
this._moduleId = moduleId;
|
||||
|
||||
$(userSelector).on('change', this._userChanged.bind(this));
|
||||
$(moduleSelector).on('change', this._moduleChanged.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
@ -47,12 +51,26 @@ define(['jquery'], function($) {
|
||||
*/
|
||||
UserCourseNavigation.prototype._userChanged = function(e) {
|
||||
var newUserId = $(e.target).val();
|
||||
var queryStr = '?user=' + newUserId + '&id=' + this._courseId;
|
||||
var queryStr = '?user=' + newUserId + '&id=' + this._courseId + '&mod=' + this._moduleId;
|
||||
document.location = this._baseUrl + queryStr;
|
||||
};
|
||||
|
||||
/**
|
||||
* The module was changed in the select list.
|
||||
*
|
||||
* @method _moduleChanged
|
||||
* @param {Event} e the event
|
||||
*/
|
||||
UserCourseNavigation.prototype._moduleChanged = function(e) {
|
||||
var newModuleId = $(e.target).val();
|
||||
var queryStr = '?mod=' + newModuleId + '&id=' + this._courseId + '&user=' + this._userId;
|
||||
document.location = this._baseUrl + queryStr;
|
||||
};
|
||||
|
||||
/** @type {Number} The id of the user. */
|
||||
UserCourseNavigation.prototype._userId = null;
|
||||
/** @type {Number} The id of the module. */
|
||||
UserCourseNavigation.prototype._moduleId = null;
|
||||
/** @type {Number} The id of the course. */
|
||||
UserCourseNavigation.prototype._courseId = null;
|
||||
/** @type {String} Plugin base url. */
|
||||
|
@ -62,9 +62,15 @@ class external extends external_api {
|
||||
'The user id',
|
||||
VALUE_REQUIRED
|
||||
);
|
||||
$moduleid = new external_value(
|
||||
PARAM_INT,
|
||||
'The module id',
|
||||
VALUE_REQUIRED
|
||||
);
|
||||
$params = array(
|
||||
'courseid' => $courseid,
|
||||
'userid' => $userid
|
||||
'userid' => $userid,
|
||||
'moduleid' => $moduleid,
|
||||
);
|
||||
return new external_function_parameters($params);
|
||||
}
|
||||
@ -74,16 +80,18 @@ class external extends external_api {
|
||||
*
|
||||
* @param int $courseid The course id
|
||||
* @param int $userid The user id
|
||||
* @param int $moduleid The module id
|
||||
* @return \stdClass
|
||||
*/
|
||||
public static function data_for_report($courseid, $userid) {
|
||||
public static function data_for_report($courseid, $userid, $moduleid) {
|
||||
global $PAGE;
|
||||
|
||||
$params = self::validate_parameters(
|
||||
self::data_for_report_parameters(),
|
||||
array(
|
||||
'courseid' => $courseid,
|
||||
'userid' => $userid
|
||||
'userid' => $userid,
|
||||
'moduleid' => $moduleid
|
||||
)
|
||||
);
|
||||
$context = context_course::instance($params['courseid']);
|
||||
@ -92,7 +100,7 @@ class external extends external_api {
|
||||
throw new coding_exception('invaliduser');
|
||||
}
|
||||
|
||||
$renderable = new output\report($params['courseid'], $params['userid']);
|
||||
$renderable = new output\report($params['courseid'], $params['userid'], $params['moduleid']);
|
||||
$renderer = $PAGE->get_renderer('report_competency');
|
||||
|
||||
$data = $renderable->export_for_template($renderer);
|
||||
|
@ -51,6 +51,8 @@ class report implements renderable, templatable {
|
||||
protected $context;
|
||||
/** @var int $courseid */
|
||||
protected $courseid;
|
||||
/** @var int $moduleid */
|
||||
protected $moduleid;
|
||||
/** @var array $competencies */
|
||||
protected $competencies;
|
||||
|
||||
@ -59,10 +61,12 @@ class report implements renderable, templatable {
|
||||
*
|
||||
* @param int $courseid The course id
|
||||
* @param int $userid The user id
|
||||
* @param int $moduleid The module id
|
||||
*/
|
||||
public function __construct($courseid, $userid) {
|
||||
public function __construct($courseid, $userid, $moduleid) {
|
||||
$this->courseid = $courseid;
|
||||
$this->userid = $userid;
|
||||
$this->moduleid = $moduleid;
|
||||
$this->context = context_course::instance($courseid);
|
||||
}
|
||||
|
||||
@ -77,6 +81,10 @@ class report implements renderable, templatable {
|
||||
|
||||
$data = new stdClass();
|
||||
$data->courseid = $this->courseid;
|
||||
$data->moduleid = $this->moduleid;
|
||||
if (empty($data->moduleid)) {
|
||||
$data->moduleid = 0;
|
||||
}
|
||||
|
||||
$course = $DB->get_record('course', array('id' => $this->courseid));
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
@ -93,6 +101,23 @@ class report implements renderable, templatable {
|
||||
$data->usercompetencies = array();
|
||||
$coursecompetencies = api::list_course_competencies($this->courseid);
|
||||
$usercompetencycourses = api::list_user_competencies_in_course($this->courseid, $user->id);
|
||||
if ($this->moduleid > 0) {
|
||||
$modulecompetencies = api::list_course_module_competencies_in_course_module($this->moduleid);
|
||||
foreach ($usercompetencycourses as $ucid => $usercompetency) {
|
||||
$found = false;
|
||||
foreach ($modulecompetencies as $mcid => $modulecompetency) {
|
||||
if ($modulecompetency->get('competencyid') == $usercompetency->get('competencyid')) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found) {
|
||||
// We need to filter out this competency.
|
||||
unset($usercompetencycourses[$ucid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$helper = new performance_helper();
|
||||
foreach ($usercompetencycourses as $usercompetencycourse) {
|
||||
|
@ -28,6 +28,7 @@ use renderer_base;
|
||||
use templatable;
|
||||
use context_course;
|
||||
use core_user\external\user_summary_exporter;
|
||||
use core_course\external\course_module_summary_exporter;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
@ -45,6 +46,9 @@ class user_course_navigation implements renderable, templatable {
|
||||
/** @var courseid */
|
||||
protected $courseid;
|
||||
|
||||
/** @var moduleid */
|
||||
protected $moduleid;
|
||||
|
||||
/** @var baseurl */
|
||||
protected $baseurl;
|
||||
|
||||
@ -53,11 +57,13 @@ class user_course_navigation implements renderable, templatable {
|
||||
*
|
||||
* @param int $userid
|
||||
* @param int $courseid
|
||||
* @param int $moduleid
|
||||
* @param string $baseurl
|
||||
*/
|
||||
public function __construct($userid, $courseid, $baseurl) {
|
||||
public function __construct($userid, $courseid, $baseurl, $moduleid) {
|
||||
$this->userid = $userid;
|
||||
$this->courseid = $courseid;
|
||||
$this->moduleid = $moduleid;
|
||||
$this->baseurl = $baseurl;
|
||||
}
|
||||
|
||||
@ -75,6 +81,7 @@ class user_course_navigation implements renderable, templatable {
|
||||
$data = new stdClass();
|
||||
$data->userid = $this->userid;
|
||||
$data->courseid = $this->courseid;
|
||||
$data->moduleid = $this->moduleid;
|
||||
$data->baseurl = $this->baseurl;
|
||||
$data->groupselector = '';
|
||||
|
||||
@ -107,6 +114,25 @@ class user_course_navigation implements renderable, templatable {
|
||||
$data->users[] = $user;
|
||||
}
|
||||
$data->hasusers = true;
|
||||
|
||||
$data->hasmodules = true;
|
||||
$data->modules = array();
|
||||
$empty = (object)['id' => 0, 'name' => get_string('nofiltersapplied')];
|
||||
$data->modules[] = $empty;
|
||||
|
||||
$modinfo = get_fast_modinfo($this->courseid);
|
||||
foreach ($modinfo->get_cms() as $cm) {
|
||||
if ($cm->uservisible) {
|
||||
$exporter = new course_module_summary_exporter(null, ['cm' => $cm]);
|
||||
$module = $exporter->export($output);
|
||||
if ($module->id == $this->moduleid) {
|
||||
$module->selected = true;
|
||||
}
|
||||
$data->modules[] = $module;
|
||||
$data->hasmodules = true;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$data->users = array();
|
||||
$data->hasusers = false;
|
||||
|
@ -31,6 +31,11 @@ $course = $DB->get_record('course', $params, '*', MUST_EXIST);
|
||||
require_login($course);
|
||||
$context = context_course::instance($course->id);
|
||||
$currentuser = optional_param('user', null, PARAM_INT);
|
||||
$currentmodule = optional_param('mod', null, PARAM_INT);
|
||||
if ($currentmodule > 0) {
|
||||
$cm = get_coursemodule_from_id('', $currentmodule, 0, false, MUST_EXIST);
|
||||
$context = context_module::instance($cm->id);
|
||||
}
|
||||
|
||||
// Fetch current active group.
|
||||
$groupmode = groups_get_course_groupmode($course);
|
||||
@ -54,6 +59,7 @@ if (empty($currentuser)) {
|
||||
$urlparams = array('id' => $id);
|
||||
$navurl = new moodle_url('/report/competency/index.php', $urlparams);
|
||||
$urlparams['user'] = $currentuser;
|
||||
$urlparams['mod'] = $currentmodule;
|
||||
$url = new moodle_url('/report/competency/index.php', $urlparams);
|
||||
|
||||
$title = get_string('pluginname', 'report_competency');
|
||||
@ -69,7 +75,7 @@ $output = $PAGE->get_renderer('report_competency');
|
||||
|
||||
echo $output->header();
|
||||
$baseurl = new moodle_url('/report/competency/index.php');
|
||||
$nav = new \report_competency\output\user_course_navigation($currentuser, $course->id, $baseurl);
|
||||
$nav = new \report_competency\output\user_course_navigation($currentuser, $course->id, $baseurl, $currentmodule);
|
||||
echo $output->render($nav);
|
||||
if ($currentuser > 0) {
|
||||
$user = core_user::get_user($currentuser);
|
||||
@ -79,12 +85,16 @@ if ($currentuser > 0) {
|
||||
'user' => $user,
|
||||
'usercontext' => $usercontext
|
||||
);
|
||||
if ($currentmodule > 0) {
|
||||
$title = get_string('filtermodule', 'report_competency', format_string($cm->name));
|
||||
}
|
||||
echo $output->context_header($userheading, 3);
|
||||
}
|
||||
echo $output->container('', 'clearfix');
|
||||
echo $output->heading($title, 3);
|
||||
|
||||
if ($currentuser > 0) {
|
||||
$page = new \report_competency\output\report($course->id, $currentuser);
|
||||
$page = new \report_competency\output\report($course->id, $currentuser, $currentmodule);
|
||||
echo $output->render($page);
|
||||
} else {
|
||||
echo $output->container('', 'clearfix');
|
||||
|
@ -27,5 +27,6 @@ $string['coursecompetencybreakdownsummary'] = 'A report of all the students in t
|
||||
$string['notrated'] = 'Not rated';
|
||||
$string['pluginname'] = 'Competency breakdown';
|
||||
$string['rating'] = 'Rating';
|
||||
$string['filtermodule'] = 'Competencies linked to "{$a}"';
|
||||
$string['usercompetencysummary'] = 'User competency summary';
|
||||
$string['privacy:metadata'] = 'The Competency breakdown plugin does not store any personal data.';
|
||||
|
@ -44,3 +44,22 @@ function report_competency_extend_navigation_course($navigation, $course, $conte
|
||||
$navigation->add($name, $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function extends the navigation with the report items
|
||||
*
|
||||
* @param navigation_node $navigation The navigation node to extend
|
||||
* @param cminfo $cm The course module.
|
||||
*/
|
||||
function report_competency_extend_navigation_module($navigation, $cm) {
|
||||
if (!get_config('core_competency', 'enabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_any_capability(array('moodle/competency:usercompetencyview', 'moodle/competency:coursecompetencymanage'),
|
||||
context_course::instance($cm->course))) {
|
||||
$url = new moodle_url('/report/competency/index.php', array('id' => $cm->course, 'mod' => $cm->id));
|
||||
$name = get_string('pluginname', 'report_competency');
|
||||
$navigation->add($name, $url, navigation_node::TYPE_SETTING, null, null);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div data-region="competency-breakdown-report" data-courseid="{{course.id}}" data-userid="{{user.id}}">
|
||||
<div data-region="competency-breakdown-report" data-courseid="{{course.id}}" data-userid="{{user.id}}" data-moduleid="{{moduleid}}">
|
||||
<div data-region="configurecoursecompetencies">
|
||||
{{#pushratingstouserplans}}
|
||||
<p class="alert">
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div class="float-right card">
|
||||
<div class="float-right card p-x-1 p-b-1">
|
||||
<p>{{{groupselector}}}</p>
|
||||
<form class="user-competency-course-navigation">
|
||||
{{#hasusers}}
|
||||
@ -11,13 +11,27 @@
|
||||
</select>
|
||||
</span>
|
||||
{{/hasusers}}
|
||||
|
||||
{{#hasmodules}}
|
||||
<span>
|
||||
<label for="module-nav-{{uniqid}}" class="accesshide">{{#str}}filterbyactivity, tool_lp{{/str}}</label>
|
||||
<select id="module-nav-{{uniqid}}">
|
||||
{{#modules}}
|
||||
<option value="{{id}}" {{#selected}}selected="selected"{{/selected}}>{{name}}</option>
|
||||
{{/modules}}
|
||||
</select>
|
||||
</span>
|
||||
{{/hasmodules}}
|
||||
</form>
|
||||
</div>
|
||||
{{#js}}
|
||||
require(['core/form-autocomplete', 'report_competency/user_course_navigation'], function(autocomplete, nav) {
|
||||
(new nav('#user-nav-{{uniqid}}', '{{baseurl}}', {{userid}}, {{courseid}}));
|
||||
(new nav('#user-nav-{{uniqid}}', '#module-nav-{{uniqid}}', '{{baseurl}}', {{userid}}, {{courseid}}, {{moduleid}}));
|
||||
{{#hasusers}}
|
||||
autocomplete.enhance('#user-nav-{{uniqid}}', false, false, {{# quote }}{{# str }}jumptouser, tool_lp{{/ str }}{{/ quote }});
|
||||
{{/hasusers}}
|
||||
{{#hasmodules}}
|
||||
autocomplete.enhance('#module-nav-{{uniqid}}', false, false, {{# quote }}{{# str }}filterbyactivity, tool_lp{{/ str }}{{/ quote }});
|
||||
{{/hasmodules}}
|
||||
});
|
||||
{{/js}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user