Merge branch 'MDL-80744-main-1' of https://github.com/ilyatregubov/moodle

This commit is contained in:
Huong Nguyen
2024-07-16 09:15:57 +07:00
72 changed files with 1368 additions and 587 deletions
@@ -0,0 +1,20 @@
issueNumber: MDL-80744
notes:
core_grades:
- message: >-
The behat step definition
behat_grade::i_confirm_in_search_within_the_gradebook_widget_exists has
been deprecated. Please use
behat_general::i_confirm_in_search_combobox_exists instead.
type: deprecated
- message: >-
The behat step definition
behat_grade::i_confirm_in_search_within_the_gradebook_widget_does_not_exist
has been deprecated. Please use
behat_general::i_confirm_in_search_combobox_does_not_exist instead.
type: deprecated
- message: >-
The behat step definition behat_grade::i_click_on_in_search_widget has
been deprecated. Please use behat_general::i_click_on_in_search_combobox
instead.
type: deprecated
@@ -112,7 +112,7 @@ Feature: Allow to mark course as completed without cron for activity completion
Given I am on the "Completion course" "grades > Single View > View" page logged in as "teacher1"
And I click on "Users" "link" in the ".page-toggler" "css_element"
And I turn editing mode on
And I click on "Student First" in the "user" search widget
And I click on "Student First" in the "Search users" search combo box
And I set the field "Override for Test assignment name" to "1"
When I set the following fields to these values:
| Grade for Test assignment name | 10.00 |
@@ -25,6 +25,17 @@ namespace core_course\output\actionbar;
*/
class renderer extends \plugin_renderer_base {
/**
* Renders the user selector trigger element in the action bar.
*
* @param user_selector $userselector The user selector object.
* @return string The HTML output.
*/
public function render_user_selector(user_selector $userselector): string {
$data = $userselector->export_for_template($this);
return parent::render_from_template($userselector->get_template(), $data);
}
/**
* Renders the group selector trigger element in the action bar.
*
@@ -0,0 +1,96 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_course\output\actionbar;
use core\output\comboboxsearch;
use moodle_url;
use stdClass;
/**
* Renderable class for the user selector element in the action bar.
*
* @package core_course
* @copyright 2024 Ilya Tregubov <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class user_selector extends comboboxsearch {
/**
* The class constructor.
*
* @param stdClass $course The course object.
* @param moodle_url $resetlink The reset link.
* @param int|null $userid The user ID.
* @param int|null $groupid The group ID.
* @param string $usersearch The user search query.
* @param int|null $instanceid The instance ID.
*/
public function __construct(
stdClass $course,
moodle_url $resetlink,
?int $userid = null,
?int $groupid = null,
string $usersearch = '',
?int $instanceid = null
) {
$userselectorontent = $this->user_selector_output($course, $resetlink, $userid, $groupid, $usersearch, $instanceid);
parent::__construct(true, $userselectorontent, null, 'user-search d-flex',
null, 'usersearchdropdown overflow-auto', null, false);
}
/**
* Method that generates the output for the user selector.
*
* @param stdClass $course The course object.
* @param moodle_url|null $resetlink The reset link.
* @param int|null $userid The user ID.
* @param int|null $groupid The group ID.
* @param string $usersearch The user search query.
* @param int|null $instanceid The instance ID.
* @return string The HTML output.
*/
private function user_selector_output(
stdClass $course,
?moodle_url $resetlink = null,
?int $userid = null,
?int $groupid = null,
string $usersearch = '',
?int $instanceid = null
): string {
global $OUTPUT;
// If the user ID is set, it indicates that a user has been selected. In this case, override the user search
// string with the full name of the selected user.
if ($userid) {
$usersearch = fullname(\core_user::get_user($userid));
}
return $OUTPUT->render_from_template('core_user/comboboxsearch/user_selector', [
'currentvalue' => $usersearch,
'courseid' => $course->id,
'instance' => $instanceid ?? rand(),
'resetlink' => $resetlink->out(false),
'group' => $groupid ?? 0,
'name' => 'usersearch',
'value' => json_encode([
'userid' => $userid,
'search' => $usersearch,
]),
]);
}
}
+2 -2
View File
@@ -1,10 +1,10 @@
define("gradereport_grader/user",["exports","core_user/comboboxsearch/user","core/url","gradereport_grader/local/user/repository"],(function(_exports,_user,_url,Repository){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
define("gradereport_grader/user",["exports","core_user/comboboxsearch/user","gradereport_grader/local/user/repository"],(function(_exports,_user,Repository){var obj;
/**
* Allow the user to search for learners within the grader report.
*
* @module gradereport_grader/user
* @copyright 2023 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_user=_interopRequireDefault(_user),_url=_interopRequireDefault(_url),Repository=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Repository);const selectors_component=".user-search",selectors_courseid='[data-region="courseid"]',courseID=document.querySelector(selectors_component).querySelector(selectors_courseid).dataset.courseid;class User extends _user.default{constructor(){super()}static init(){return new User}fetchDataset(){return Repository.userFetch(courseID).then((r=>r.users))}selectAllResultsLink(){return _url.default.relativeUrl("/grade/report/grader/index.php",{id:courseID,gpr_search:this.getSearchTerm()},!1)}selectOneLink(userID){return _url.default.relativeUrl("/grade/report/grader/index.php",{id:courseID,gpr_search:this.getSearchTerm(),gpr_userid:userID},!1)}}return _exports.default=User,_exports.default}));
*/function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_user=(obj=_user)&&obj.__esModule?obj:{default:obj},Repository=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Repository);const selectors_component=".user-search",selectors_courseid='[data-region="courseid"]',courseID=document.querySelector(selectors_component).querySelector(selectors_courseid).dataset.courseid;class User extends _user.default{constructor(baseUrl){super(),this.baseUrl=baseUrl}static init(baseUrl){return new User(baseUrl)}fetchDataset(){return Repository.userFetch(courseID).then((r=>r.users))}selectAllResultsLink(){const url=new URL(this.baseUrl);return url.searchParams.set("gpr_search",this.getSearchTerm()),url.toString()}selectOneLink(userID){const url=new URL(this.baseUrl);return url.searchParams.set("gpr_search",this.getSearchTerm()),url.searchParams.set("gpr_userid",userID),url.toString()}}return _exports.default=User,_exports.default}));
//# sourceMappingURL=user.min.js.map
@@ -1 +1 @@
{"version":3,"file":"user.min.js","sources":["../src/user.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Allow the user to search for learners within the grader report.\n *\n * @module gradereport_grader/user\n * @copyright 2023 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport UserSearch from 'core_user/comboboxsearch/user';\nimport Url from 'core/url';\nimport * as Repository from 'gradereport_grader/local/user/repository';\n\n// Define our standard lookups.\nconst selectors = {\n component: '.user-search',\n courseid: '[data-region=\"courseid\"]',\n};\nconst component = document.querySelector(selectors.component);\nconst courseID = component.querySelector(selectors.courseid).dataset.courseid;\n\nexport default class User extends UserSearch {\n\n constructor() {\n super();\n }\n\n static init() {\n return new User();\n }\n\n /**\n * Get the data we will be searching against in this component.\n *\n * @returns {Promise<*>}\n */\n fetchDataset() {\n return Repository.userFetch(courseID).then((r) => r.users);\n }\n\n /**\n * Build up the view all link.\n *\n * @returns {string|*}\n */\n selectAllResultsLink() {\n return Url.relativeUrl('/grade/report/grader/index.php', {\n id: courseID,\n gpr_search: this.getSearchTerm()\n }, false);\n }\n\n /**\n * Build up the link that is dedicated to a particular result.\n *\n * @param {Number} userID The ID of the user selected.\n * @returns {string|*}\n */\n selectOneLink(userID) {\n return Url.relativeUrl('/grade/report/grader/index.php', {\n id: courseID,\n gpr_search: this.getSearchTerm(),\n gpr_userid: userID,\n }, false);\n }\n}\n"],"names":["selectors","courseID","document","querySelector","dataset","courseid","User","UserSearch","constructor","fetchDataset","Repository","userFetch","then","r","users","selectAllResultsLink","Url","relativeUrl","id","gpr_search","this","getSearchTerm","selectOneLink","userID","gpr_userid"],"mappings":";;;;;;;q0BA2BMA,oBACS,eADTA,mBAEQ,2BAGRC,SADYC,SAASC,cAAcH,qBACdG,cAAcH,oBAAoBI,QAAQC,eAEhDC,aAAaC,cAE9BC,2CAKW,IAAIF,KAQfG,sBACWC,WAAWC,UAAUV,UAAUW,MAAMC,GAAMA,EAAEC,QAQxDC,8BACWC,aAAIC,YAAY,iCAAkC,CACrDC,GAAIjB,SACJkB,WAAYC,KAAKC,kBAClB,GASPC,cAAcC,eACHP,aAAIC,YAAY,iCAAkC,CACrDC,GAAIjB,SACJkB,WAAYC,KAAKC,gBACjBG,WAAYD,SACb"}
{"version":3,"file":"user.min.js","sources":["../src/user.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Allow the user to search for learners within the grader report.\n *\n * @module gradereport_grader/user\n * @copyright 2023 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport UserSearch from 'core_user/comboboxsearch/user';\nimport * as Repository from 'gradereport_grader/local/user/repository';\n\n// Define our standard lookups.\nconst selectors = {\n component: '.user-search',\n courseid: '[data-region=\"courseid\"]',\n};\nconst component = document.querySelector(selectors.component);\nconst courseID = component.querySelector(selectors.courseid).dataset.courseid;\n\nexport default class User extends UserSearch {\n\n /**\n * Construct the class.\n * @param {string} baseUrl The base URL for the page.\n */\n constructor(baseUrl) {\n super();\n this.baseUrl = baseUrl;\n }\n\n static init(baseUrl) {\n return new User(baseUrl);\n }\n\n /**\n * Get the data we will be searching against in this component.\n *\n * @returns {Promise<*>}\n */\n fetchDataset() {\n return Repository.userFetch(courseID).then((r) => r.users);\n }\n\n /**\n * Build up the view all link.\n *\n * @returns {string|*}\n */\n selectAllResultsLink() {\n const url = new URL(this.baseUrl);\n url.searchParams.set('gpr_search', this.getSearchTerm());\n return url.toString();\n }\n\n /**\n * Build up the link that is dedicated to a particular result.\n *\n * @param {Number} userID The ID of the user selected.\n * @returns {string|*}\n */\n selectOneLink(userID) {\n const url = new URL(this.baseUrl);\n url.searchParams.set('gpr_search', this.getSearchTerm());\n url.searchParams.set('gpr_userid', userID);\n return url.toString();\n }\n}\n"],"names":["selectors","courseID","document","querySelector","dataset","courseid","User","UserSearch","constructor","baseUrl","fetchDataset","Repository","userFetch","then","r","users","selectAllResultsLink","url","URL","this","searchParams","set","getSearchTerm","toString","selectOneLink","userID"],"mappings":";;;;;;;skCA0BMA,oBACS,eADTA,mBAEQ,2BAGRC,SADYC,SAASC,cAAcH,qBACdG,cAAcH,oBAAoBI,QAAQC,eAEhDC,aAAaC,cAM9BC,YAAYC,sBAEHA,QAAUA,oBAGPA,gBACD,IAAIH,KAAKG,SAQpBC,sBACWC,WAAWC,UAAUX,UAAUY,MAAMC,GAAMA,EAAEC,QAQxDC,6BACUC,IAAM,IAAIC,IAAIC,KAAKV,gBACzBQ,IAAIG,aAAaC,IAAI,aAAcF,KAAKG,iBACjCL,IAAIM,WASfC,cAAcC,cACJR,IAAM,IAAIC,IAAIC,KAAKV,gBACzBQ,IAAIG,aAAaC,IAAI,aAAcF,KAAKG,iBACxCL,IAAIG,aAAaC,IAAI,aAAcI,QAC5BR,IAAIM"}
+15 -13
View File
@@ -21,7 +21,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import UserSearch from 'core_user/comboboxsearch/user';
import Url from 'core/url';
import * as Repository from 'gradereport_grader/local/user/repository';
// Define our standard lookups.
@@ -34,12 +33,17 @@ const courseID = component.querySelector(selectors.courseid).dataset.courseid;
export default class User extends UserSearch {
constructor() {
/**
* Construct the class.
* @param {string} baseUrl The base URL for the page.
*/
constructor(baseUrl) {
super();
this.baseUrl = baseUrl;
}
static init() {
return new User();
static init(baseUrl) {
return new User(baseUrl);
}
/**
@@ -57,10 +61,9 @@ export default class User extends UserSearch {
* @returns {string|*}
*/
selectAllResultsLink() {
return Url.relativeUrl('/grade/report/grader/index.php', {
id: courseID,
gpr_search: this.getSearchTerm()
}, false);
const url = new URL(this.baseUrl);
url.searchParams.set('gpr_search', this.getSearchTerm());
return url.toString();
}
/**
@@ -70,10 +73,9 @@ export default class User extends UserSearch {
* @returns {string|*}
*/
selectOneLink(userID) {
return Url.relativeUrl('/grade/report/grader/index.php', {
id: courseID,
gpr_search: this.getSearchTerm(),
gpr_userid: userID,
}, false);
const url = new URL(this.baseUrl);
url.searchParams.set('gpr_search', this.getSearchTerm());
url.searchParams.set('gpr_userid', userID);
return url.toString();
}
}
@@ -117,30 +117,14 @@ class action_bar extends \core_grades\output\action_bar {
}
$resetlink = new moodle_url('/grade/report/grader/index.php', ['id' => $courseid]);
$searchinput = $OUTPUT->render_from_template('core_user/comboboxsearch/user_selector', [
'currentvalue' => $this->usersearch,
'courseid' => $courseid,
'instance' => rand(),
'resetlink' => $resetlink->out(false),
'group' => 0,
'name' => 'usersearch',
'value' => json_encode([
'userid' => $this->userid,
'search' => $this->usersearch,
]),
]);
$searchdropdown = new comboboxsearch(
true,
$searchinput,
null,
'user-search d-flex',
null,
'usersearchdropdown overflow-auto',
null,
false,
$userselectorrenderer = new \core_course\output\actionbar\user_selector(
course: $course,
resetlink: $resetlink,
userid: $this->userid,
groupid: 0,
usersearch: $this->usersearch
);
$data['searchdropdown'] = $searchdropdown->export_for_template($output);
$data['searchdropdown'] = $userselectorrenderer->export_for_template($output);
// The collapsed column dialog is aligned to the edge of the screen, we need to place it such that it also aligns.
$collapsemenudirection = right_to_left() ? 'dropdown-menu-left' : 'dropdown-menu-right';
+2 -2
View File
@@ -45,11 +45,12 @@ $graderreportsifirst = optional_param('sifirst', null, PARAM_NOTAGS);
$graderreportsilast = optional_param('silast', null, PARAM_NOTAGS);
$studentsperpage = optional_param('perpage', null, PARAM_INT);
$baseurl = new moodle_url('/grade/report/grader/index.php', ['id' => $courseid]);
$PAGE->set_url(new moodle_url('/grade/report/grader/index.php', array('id'=>$courseid)));
$PAGE->set_pagelayout('report');
$PAGE->requires->js_call_amd('gradereport_grader/stickycolspan', 'init');
$PAGE->requires->js_call_amd('gradereport_grader/user', 'init');
$PAGE->requires->js_call_amd('gradereport_grader/user', 'init', [$baseurl->out(false)]);
$PAGE->requires->js_call_amd('gradereport_grader/feedback_modal', 'init');
$PAGE->requires->js_call_amd('core_grades/gradebooksetup_forms', 'init');
@@ -60,7 +61,6 @@ if (!$course = $DB->get_record('course', array('id' => $courseid))) {
// Conditionally add the group JS if we have groups enabled.
if ($course->groupmode) {
$baseurl = new moodle_url('/grade/report/grader/index.php', ['id' => $courseid]);
$PAGE->requires->js_call_amd('core_course/actionbar/group', 'init', [$baseurl->out(false)]);
}
@@ -36,13 +36,13 @@ Feature: Group searching functionality within the grader report.
Then ".groupsearchwidget" "css_element" should not exist
Scenario: A teacher can search for and find a group to display
Given I confirm "Tutor group" in "group" search within the gradebook widget exists
And I confirm "Marker group" in "group" search within the gradebook widget exists
Given I confirm "Tutor group" exists in the "Search groups" search combo box
And I confirm "Marker group" exists in the "Search groups" search combo box
When I set the field "Search groups" to "tutor"
And I wait until "Marker group" "option_role" does not exist
Then I confirm "Tutor group" in "group" search within the gradebook widget exists
And I confirm "Marker group" in "group" search within the gradebook widget does not exist
And I click on "Tutor group" in the "group" search widget
Then I confirm "Tutor group" exists in the "Search groups" search combo box
And I confirm "Marker group" does not exist in the "Search groups" search combo box
And I click on "Tutor group" in the "Search groups" search combo box
# The search input remains in the field on reload this is in keeping with other search implementations.
And I click on ".groupsearchwidget" "css_element"
And the field "Search groups" matches value "tutor"
@@ -52,22 +52,22 @@ Feature: Group searching functionality within the grader report.
Scenario: A teacher can only see the group members in the 'user' search widget after selecting a group option
# Confirm that all users are initially displayed in the 'user' search widget.
Given I set the field "Search users" to "Student"
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Student 2" in "user" search within the gradebook widget exists
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Student 2" exists in the "Search users" search combo box
# Select a particular group from the 'group' search widget.
When I click on "Default group" in the "group" search widget
When I click on "Default group" in the "Search groups" search combo box
# Confirm that only users which are members of the selected group are displayed in the 'user' search widget.
And I set the field "Search users" to "Student"
Then I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Student 2" in "user" search within the gradebook widget does not exist
And I click on "Tutor group" in the "group" search widget
Then I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Student 2" does not exist in the "Search users" search combo box
And I click on "Tutor group" in the "Search groups" search combo box
And I set the field "Search users" to "Student"
And I confirm "Student 1" in "user" search within the gradebook widget does not exist
And I confirm "Student 2" in "user" search within the gradebook widget does not exist
And I click on "All participants" in the "group" search widget
And I confirm "Student 1" does not exist in the "Search users" search combo box
And I confirm "Student 2" does not exist in the "Search users" search combo box
And I click on "All participants" in the "Search groups" search combo box
And I set the field "Search users" to "Student"
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Student 2" in "user" search within the gradebook widget exists
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Student 2" exists in the "Search users" search combo box
@accessibility
Scenario: A teacher can set focus and search using the input with a keyboard
@@ -150,7 +150,7 @@ Feature: Within the grader report, test that we can open our generic filter drop
Scenario: A teacher can search and then filter by first or last name
Given I set the field "Search users" to "Student 1"
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And I click on "Filter by name" "combobox"
And I select "S" in the "First name" "core_grades > initials bar"
When I press "Apply"
@@ -54,8 +54,8 @@ Feature: Within the grader report, test that we can search for users
| Teacher 1 |
When I set the field "Search users" to "Turtle"
And I wait until "View all results (1)" "option_role" exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget does not exist
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
And I confirm "User Example" does not exist in the "Search users" search combo box
And I click on "Turtle Manatee" "list_item"
# Business case: This will trigger a page reload and can not dynamically update the table.
And I wait until the page is ready
@@ -76,7 +76,7 @@ Feature: Within the grader report, test that we can search for users
Scenario: A teacher can search the grader report to find specified users
# Case: Standard search.
Given I click on "Dummy" in the "user" search widget
Given I click on "Dummy" in the "Search users" search combo box
And the following should exist in the "user-grades" table:
| -1- |
| Dummy User |
@@ -106,14 +106,14 @@ Feature: Within the grader report, test that we can search for users
# Case: Multiple users found and select only one result.
Then I set the field "Search users" to "User"
And I wait until "View all results (3)" "option_role" exists
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget does not exist
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" does not exist in the "Search users" search combo box
# Check if the matched field names (by lines) includes some identifiable info to help differentiate similar users.
And I confirm "User (student2@example.com)" in "user" search within the gradebook widget exists
And I confirm "User (student3@example.com)" in "user" search within the gradebook widget exists
And I confirm "User (student4@example.com)" in "user" search within the gradebook widget exists
And I confirm "User (student2@example.com)" exists in the "Search users" search combo box
And I confirm "User (student3@example.com)" exists in the "Search users" search combo box
And I confirm "User (student4@example.com)" exists in the "Search users" search combo box
And I click on "Dummy User" "list_item"
And I wait until the page is ready
And the following should exist in the "user-grades" table:
@@ -156,7 +156,7 @@ Feature: Within the grader report, test that we can search for users
| Dummy User |
Scenario: A teacher can quickly tell that a search is active on the current table
When I click on "Turtle" in the "user" search widget
When I click on "Turtle" in the "Search users" search combo box
# The search input should contain the name of the user we have selected, so that it is clear that the result pertains to a specific user.
Then the field "Search users" matches value "Turtle Manatee"
# Test if we can then further retain the turtle result set and further filter from there.
@@ -171,54 +171,54 @@ Feature: Within the grader report, test that we can search for users
And I set the field "Search users" to "@example.com"
And I wait until "View all results (5)" "option_role" exists
# Note: All learners match this email & showing emails is current default.
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the country field.
When I set the field "Search users" to "JP"
And I wait until "Turtle Manatee" "list_item" does not exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
# Search on the city field.
And I set the field "Search users" to "Hanoi"
And I wait until "User Test" "list_item" does not exist
Then I confirm "Student 1" in "user" search within the gradebook widget exists
Then I confirm "Student 1" exists in the "Search users" search combo box
# Search on the institution field.
And I set the field "Search users" to "ABCD"
And I wait until "Dummy User" "list_item" exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the department field.
And I set the field "Search users" to "ABC3"
And I wait until "User Example" "list_item" does not exist
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the phone1 field.
And I set the field "Search users" to "4365899871"
And I wait until "User Test" "list_item" does not exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
# Search on the phone2 field.
And I set the field "Search users" to "2149871323"
And I wait until "Dummy User" "list_item" does not exist
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "User Test" exists in the "Search users" search combo box
# Search on the institution field then press enter to show the record set.
And I set the field "Search users" to "ABC"
And I wait until "Turtle Manatee" "list_item" exists
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I press the down key
And I press the enter key
And I wait "1" seconds
@@ -292,7 +292,7 @@ Feature: Within the grader report, test that we can search for users
And the focused element is "Clear search input" "button"
And I press the enter key
And I wait until the page is ready
And I confirm "Turtle Manatee" in "user" search within the gradebook widget does not exist
And I confirm "Turtle Manatee" does not exist in the "Search users" search combo box
Scenario: Once a teacher searches, it'll apply the currently set filters and inform the teacher as such
# Set up a basic filtering case.
@@ -314,7 +314,7 @@ Feature: Within the grader report, test that we can search for users
# Begin the search checking if we are adhering the filters.
When I set the field "Search users" to "Turtle"
Then I confirm "Turtle Manatee" in "user" search within the gradebook widget does not exist
Then I confirm "Turtle Manatee" does not exist in the "Search users" search combo box
Scenario: A teacher can reset the search and filters all at once
Given I set the field "Search users" to "Turtle"
@@ -329,7 +329,7 @@ Feature: Within the grader report, test that we can search for users
And the following should exist in the "user-grades" table:
| -1- |
| Turtle Manatee |
And I click on "Default group" in the "group" search widget
And I click on "Default group" in the "Search groups" search combo box
And the following should exist in the "user-grades" table:
| -1- |
| Turtle Manatee |
@@ -353,7 +353,7 @@ Feature: Within the grader report, test that we can search for users
When I set the field "Search users" to "42"
# One of the users' phone numbers also matches.
And I wait until "View all results (2)" "option_role" exists
Then I confirm "Student s42" in "user" search within the gradebook widget exists
Then I confirm "Student s42" exists in the "Search users" search combo box
Scenario: As a teacher I save grades using search and pagination
Given "42" "users" exist with the following data:
+1 -94
View File
@@ -485,108 +485,15 @@ abstract class grade_report {
// A user wants to return a subset of learners that match their search criteria.
if ($this->usersearch !== '' && $this->userid === -1) {
// Get the fields for all contexts because there is a special case later where it allows
// matches of fields you can't access if they are on your own account.
$userfields = fields::for_identity(null, false)->with_userpic();
['mappings' => $mappings] = (array)$userfields->get_sql('u', true);
[
'where' => $keywordswhere,
'params' => $keywordsparams,
] = $this->get_users_search_sql($mappings, $userfields->get_required_fields());
] = \core_user::get_users_search_sql($this->context, $this->usersearch);
$this->userwheresql .= " AND $keywordswhere";
$this->userwheresql_params = array_merge($this->userwheresql_params, $keywordsparams);
}
}
/**
* Prepare SQL where clause and associated parameters for any user searching being performed.
* This mostly came from core_user\table\participants_search with some slight modifications four our use case.
*
* @param array $mappings Array of field mappings (fieldname => SQL code for the value)
* @param array $userfields An array that we cast from user profile fields to search within.
* @return array SQL query data in the format ['where' => '', 'params' => []].
*/
protected function get_users_search_sql(array $mappings, array $userfields): array {
global $DB, $USER;
$canviewfullnames = has_capability('moodle/site:viewfullnames', $this->context);
$params = [];
$searchkey1 = 'search01';
$searchkey2 = 'search02';
$searchkey3 = 'search03';
$conditions = [];
// Search by fullname.
[$fullname, $fullnameparams] = fields::get_sql_fullname('u', $canviewfullnames);
$conditions[] = $DB->sql_like($fullname, ':' . $searchkey1, false, false);
$params = array_merge($params, $fullnameparams);
// Search by email.
$email = $DB->sql_like('email', ':' . $searchkey2, false, false);
if (!in_array('email', $userfields)) {
$maildisplay = 'maildisplay0';
$userid1 = 'userid01';
// Prevent users who hide their email address from being found by others
// who aren't allowed to see hidden email addresses.
$email = "(". $email ." AND (" .
"u.maildisplay <> :$maildisplay " .
"OR u.id = :$userid1". // Users can always find themselves.
"))";
$params[$maildisplay] = core_user::MAILDISPLAY_HIDE;
$params[$userid1] = $USER->id;
}
$conditions[] = $email;
// Search by idnumber.
$idnumber = $DB->sql_like('idnumber', ':' . $searchkey3, false, false);
if (!in_array('idnumber', $userfields)) {
$userid2 = 'userid02';
// Users who aren't allowed to see idnumbers should at most find themselves
// when searching for an idnumber.
$idnumber = "(". $idnumber . " AND u.id = :$userid2)";
$params[$userid2] = $USER->id;
}
$conditions[] = $idnumber;
// Search all user identify fields.
$extrasearchfields = fields::get_identity_fields(null, false);
foreach ($extrasearchfields as $fieldindex => $extrasearchfield) {
if (in_array($extrasearchfield, ['email', 'idnumber', 'country'])) {
// Already covered above.
continue;
}
// The param must be short (max 32 characters) so don't include field name.
$param = $searchkey3 . '_ident' . $fieldindex;
$fieldsql = $mappings[$extrasearchfield];
$condition = $DB->sql_like($fieldsql, ':' . $param, false, false);
$params[$param] = "%$this->usersearch%";
if (!in_array($extrasearchfield, $userfields)) {
// User cannot see this field, but allow match if their own account.
$userid3 = 'userid03_ident' . $fieldindex;
$condition = "(". $condition . " AND u.id = :$userid3)";
$params[$userid3] = $USER->id;
}
$conditions[] = $condition;
}
$where = "(". implode(" OR ", $conditions) .") ";
$params[$searchkey1] = "%$this->usersearch%";
$params[$searchkey2] = "%$this->usersearch%";
$params[$searchkey3] = "%$this->usersearch%";
return [
'where' => $where,
'params' => $params,
];
}
/**
* Returns an arrow icon inside an <a> tag, for the purpose of sorting a column.
* @param string $direction
+1 -1
View File
@@ -1,3 +1,3 @@
define("gradereport_singleview/grade",["exports","core_grades/comboboxsearch/grade","core/url"],(function(_exports,_grade,_url){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_grade=_interopRequireDefault(_grade),_url=_interopRequireDefault(_url);const selectors_component=".grade-search",selectors_courseid='[data-region="courseid"]',component=document.querySelector(selectors_component);class GradeItems extends _grade.default{constructor(){var obj,key,value;super(),obj=this,key="courseID",value=component.querySelector(selectors_courseid).dataset.courseid,key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}static init(){return new GradeItems}selectOneLink(gradeID){return _url.default.relativeUrl("/grade/report/singleview/index.php",{id:this.courseID,gradesearchvalue:this.getSearchTerm(),item:"grade",itemid:gradeID},!1)}}return _exports.default=GradeItems,_exports.default}));
define("gradereport_singleview/grade",["exports","core_grades/comboboxsearch/grade"],(function(_exports,_grade){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_grade=(obj=_grade)&&obj.__esModule?obj:{default:obj};const selectors_component=".grade-search",selectors_courseid='[data-region="courseid"]',component=document.querySelector(selectors_component);class GradeItems extends _grade.default{constructor(baseUrl){super(),function(obj,key,value){key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}(this,"courseID",component.querySelector(selectors_courseid).dataset.courseid),this.baseUrl=baseUrl}static init(baseUrl){return new GradeItems(baseUrl)}selectOneLink(gradeID){const url=new URL(this.baseUrl);return url.searchParams.set("gradesearchvalue",this.getSearchTerm()),url.searchParams.set("item","grade"),url.searchParams.set("itemid",gradeID),url.toString()}}return _exports.default=GradeItems,_exports.default}));
//# sourceMappingURL=grade.min.js.map
@@ -1 +1 @@
{"version":3,"file":"grade.min.js","sources":["../src/grade.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Allow the user to search for grades within the singleview report.\n *\n * @module gradereport_singleview/grade\n * @copyright 2023 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport GradeItemSearch from 'core_grades/comboboxsearch/grade';\nimport Url from 'core/url';\n\n// Define our standard lookups.\nconst selectors = {\n component: '.grade-search',\n courseid: '[data-region=\"courseid\"]',\n};\nconst component = document.querySelector(selectors.component);\n\nexport default class GradeItems extends GradeItemSearch {\n\n courseID = component.querySelector(selectors.courseid).dataset.courseid;\n\n constructor() {\n super();\n }\n\n static init() {\n return new GradeItems();\n }\n\n /**\n * Build up the link that is dedicated to a particular result.\n *\n * @param {Number} gradeID The ID of the grade item selected.\n * @returns {string|*}\n */\n selectOneLink(gradeID) {\n return Url.relativeUrl('/grade/report/singleview/index.php', {\n id: this.courseID,\n gradesearchvalue: this.getSearchTerm(),\n item: 'grade',\n itemid: gradeID,\n }, false);\n }\n}\n"],"names":["selectors","component","document","querySelector","GradeItems","GradeItemSearch","constructor","dataset","courseid","selectOneLink","gradeID","Url","relativeUrl","id","this","courseID","gradesearchvalue","getSearchTerm","item","itemid"],"mappings":"gXA0BMA,oBACS,gBADTA,mBAEQ,2BAERC,UAAYC,SAASC,cAAcH,2BAEpBI,mBAAmBC,eAIpCC,sEAFWL,UAAUE,cAAcH,oBAAoBO,QAAQC,+IAOpD,IAAIJ,WASfK,cAAcC,gBACHC,aAAIC,YAAY,qCAAsC,CACzDC,GAAIC,KAAKC,SACTC,iBAAkBF,KAAKG,gBACvBC,KAAM,QACNC,OAAQT,UACT"}
{"version":3,"file":"grade.min.js","sources":["../src/grade.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Allow the user to search for grades within the singleview report.\n *\n * @module gradereport_singleview/grade\n * @copyright 2023 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport GradeItemSearch from 'core_grades/comboboxsearch/grade';\n\n// Define our standard lookups.\nconst selectors = {\n component: '.grade-search',\n courseid: '[data-region=\"courseid\"]',\n};\nconst component = document.querySelector(selectors.component);\n\nexport default class GradeItems extends GradeItemSearch {\n\n courseID = component.querySelector(selectors.courseid).dataset.courseid;\n\n /**\n * Construct the class.\n *\n * @param {string} baseUrl The base URL for the page.\n */\n constructor(baseUrl) {\n super();\n this.baseUrl = baseUrl;\n }\n\n static init(baseUrl) {\n return new GradeItems(baseUrl);\n }\n\n /**\n * Build up the link that is dedicated to a particular result.\n *\n * @param {Number} gradeID The ID of the grade item selected.\n * @returns {string|*}\n */\n selectOneLink(gradeID) {\n const url = new URL(this.baseUrl);\n url.searchParams.set('gradesearchvalue', this.getSearchTerm());\n url.searchParams.set('item', 'grade');\n url.searchParams.set('itemid', gradeID);\n return url.toString();\n }\n}\n"],"names":["selectors","component","document","querySelector","GradeItems","GradeItemSearch","constructor","baseUrl","dataset","courseid","selectOneLink","gradeID","url","URL","this","searchParams","set","getSearchTerm","toString"],"mappings":"oQAyBMA,oBACS,gBADTA,mBAEQ,2BAERC,UAAYC,SAASC,cAAcH,2BAEpBI,mBAAmBC,eASpCC,YAAYC,2KAPDN,UAAUE,cAAcH,oBAAoBQ,QAAQC,eAStDF,QAAUA,oBAGPA,gBACD,IAAIH,WAAWG,SAS1BG,cAAcC,eACJC,IAAM,IAAIC,IAAIC,KAAKP,gBACzBK,IAAIG,aAAaC,IAAI,mBAAoBF,KAAKG,iBAC9CL,IAAIG,aAAaC,IAAI,OAAQ,SAC7BJ,IAAIG,aAAaC,IAAI,SAAUL,SACxBC,IAAIM"}
+2 -2
View File
@@ -1,10 +1,10 @@
define("gradereport_singleview/user",["exports","core_user/comboboxsearch/user","core/url","core/templates","core_grades/searchwidget/repository"],(function(_exports,_user,_url,_templates,Repository){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
define("gradereport_singleview/user",["exports","core_user/comboboxsearch/user","core/templates","core_grades/searchwidget/repository"],(function(_exports,_user,_templates,Repository){var obj;
/**
* Allow the user to search for learners within the singleview report.
*
* @module gradereport_singleview/user
* @copyright 2023 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_user=_interopRequireDefault(_user),_url=_interopRequireDefault(_url),Repository=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Repository);class User extends _user.default{constructor(){super()}static init(){return new User}async renderDropdown(){const{html:html,js:js}=await(0,_templates.renderForPromise)("core_user/comboboxsearch/resultset",{instance:this.instance,users:this.getMatchedResults().slice(0,5),hasresults:this.getMatchedResults().length>0,searchterm:this.getSearchTerm()});(0,_templates.replaceNodeContents)(this.getHTMLElements().searchDropdown,html,js),this.searchInput.removeAttribute("aria-activedescendant")}selectAllResultsLink(){return null}selectOneLink(userID){return _url.default.relativeUrl("/grade/report/singleview/index.php",{id:this.courseID,searchvalue:this.getSearchTerm(),item:"user",userid:userID},!1)}fetchDataset(){const gts="string"==typeof this.groupID&&""===this.groupID?0:this.groupID;return Repository.userFetch(this.courseID,gts).then((r=>r.users))}}return _exports.default=User,_exports.default}));
*/function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_user=(obj=_user)&&obj.__esModule?obj:{default:obj},Repository=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Repository);class User extends _user.default{constructor(baseUrl){super(),this.baseUrl=baseUrl}static init(baseUrl){return new User(baseUrl)}async renderDropdown(){const{html:html,js:js}=await(0,_templates.renderForPromise)("core_user/comboboxsearch/resultset",{instance:this.instance,users:this.getMatchedResults().slice(0,5),hasresults:this.getMatchedResults().length>0,searchterm:this.getSearchTerm()});(0,_templates.replaceNodeContents)(this.getHTMLElements().searchDropdown,html,js),this.searchInput.removeAttribute("aria-activedescendant")}selectAllResultsLink(){return null}selectOneLink(userID){const url=new URL(this.baseUrl);return url.searchParams.set("searchvalue",this.getSearchTerm()),url.searchParams.set("item","user"),url.searchParams.set("userid",userID),url.toString()}fetchDataset(){const gts="string"==typeof this.groupID&&""===this.groupID?0:this.groupID;return Repository.userFetch(this.courseID,gts).then((r=>r.users))}}return _exports.default=User,_exports.default}));
//# sourceMappingURL=user.min.js.map
@@ -1 +1 @@
{"version":3,"file":"user.min.js","sources":["../src/user.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Allow the user to search for learners within the singleview report.\n *\n * @module gradereport_singleview/user\n * @copyright 2023 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport UserSearch from 'core_user/comboboxsearch/user';\nimport Url from 'core/url';\nimport {renderForPromise, replaceNodeContents} from 'core/templates';\nimport * as Repository from 'core_grades/searchwidget/repository';\n\nexport default class User extends UserSearch {\n\n constructor() {\n super();\n }\n\n static init() {\n return new User();\n }\n\n /**\n * Build the content then replace the node.\n */\n async renderDropdown() {\n const {html, js} = await renderForPromise('core_user/comboboxsearch/resultset', {\n instance: this.instance,\n users: this.getMatchedResults().slice(0, 5),\n hasresults: this.getMatchedResults().length > 0,\n searchterm: this.getSearchTerm(),\n });\n replaceNodeContents(this.getHTMLElements().searchDropdown, html, js);\n // Remove aria-activedescendant when the available options change.\n this.searchInput.removeAttribute('aria-activedescendant');\n }\n\n /**\n * Stub out default required function unused here.\n * @returns {null}\n */\n selectAllResultsLink() {\n return null;\n }\n\n /**\n * Build up the view all link that is dedicated to a particular result.\n *\n * @param {Number} userID The ID of the user selected.\n * @returns {string|*}\n */\n selectOneLink(userID) {\n return Url.relativeUrl('/grade/report/singleview/index.php', {\n id: this.courseID,\n searchvalue: this.getSearchTerm(),\n item: 'user',\n userid: userID,\n }, false);\n }\n\n /**\n * Get the data we will be searching against in this component.\n *\n * @returns {Promise<*>}\n */\n fetchDataset() {\n // Small typing checks as sometimes groups don't exist therefore the element returns a empty string.\n const gts = typeof (this.groupID) === \"string\" && this.groupID === '' ? 0 : this.groupID;\n return Repository.userFetch(this.courseID, gts).then((r) => r.users);\n }\n}\n"],"names":["User","UserSearch","constructor","html","js","instance","this","users","getMatchedResults","slice","hasresults","length","searchterm","getSearchTerm","getHTMLElements","searchDropdown","searchInput","removeAttribute","selectAllResultsLink","selectOneLink","userID","Url","relativeUrl","id","courseID","searchvalue","item","userid","fetchDataset","gts","groupID","Repository","userFetch","then","r"],"mappings":";;;;;;;q0BA2BqBA,aAAaC,cAE9BC,2CAKW,IAAIF,kCAOLG,KAACA,KAADC,GAAOA,UAAY,+BAAiB,qCAAsC,CAC5EC,SAAUC,KAAKD,SACfE,MAAOD,KAAKE,oBAAoBC,MAAM,EAAG,GACzCC,WAAYJ,KAAKE,oBAAoBG,OAAS,EAC9CC,WAAYN,KAAKO,qDAEDP,KAAKQ,kBAAkBC,eAAgBZ,KAAMC,SAE5DY,YAAYC,gBAAgB,yBAOrCC,8BACW,KASXC,cAAcC,eACHC,aAAIC,YAAY,qCAAsC,CACzDC,GAAIjB,KAAKkB,SACTC,YAAanB,KAAKO,gBAClBa,KAAM,OACNC,OAAQP,SACT,GAQPQ,qBAEUC,IAAgC,iBAAlBvB,KAAKwB,SAA0C,KAAjBxB,KAAKwB,QAAiB,EAAIxB,KAAKwB,eAC1EC,WAAWC,UAAU1B,KAAKkB,SAAUK,KAAKI,MAAMC,GAAMA,EAAE3B"}
{"version":3,"file":"user.min.js","sources":["../src/user.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Allow the user to search for learners within the singleview report.\n *\n * @module gradereport_singleview/user\n * @copyright 2023 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport UserSearch from 'core_user/comboboxsearch/user';\nimport {renderForPromise, replaceNodeContents} from 'core/templates';\nimport * as Repository from 'core_grades/searchwidget/repository';\n\nexport default class User extends UserSearch {\n\n /**\n * Construct the class.\n *\n * @param {string} baseUrl The base URL for the page.\n */\n constructor(baseUrl) {\n super();\n this.baseUrl = baseUrl;\n }\n\n static init(baseUrl) {\n return new User(baseUrl);\n }\n\n /**\n * Build the content then replace the node.\n */\n async renderDropdown() {\n const {html, js} = await renderForPromise('core_user/comboboxsearch/resultset', {\n instance: this.instance,\n users: this.getMatchedResults().slice(0, 5),\n hasresults: this.getMatchedResults().length > 0,\n searchterm: this.getSearchTerm(),\n });\n replaceNodeContents(this.getHTMLElements().searchDropdown, html, js);\n // Remove aria-activedescendant when the available options change.\n this.searchInput.removeAttribute('aria-activedescendant');\n }\n\n /**\n * Stub out default required function unused here.\n * @returns {null}\n */\n selectAllResultsLink() {\n return null;\n }\n\n /**\n * Build up the view all link that is dedicated to a particular result.\n *\n * @param {Number} userID The ID of the user selected.\n * @returns {string|*}\n */\n selectOneLink(userID) {\n const url = new URL(this.baseUrl);\n url.searchParams.set('searchvalue', this.getSearchTerm());\n url.searchParams.set('item', 'user');\n url.searchParams.set('userid', userID);\n return url.toString();\n }\n\n /**\n * Get the data we will be searching against in this component.\n *\n * @returns {Promise<*>}\n */\n fetchDataset() {\n // Small typing checks as sometimes groups don't exist therefore the element returns a empty string.\n const gts = typeof (this.groupID) === \"string\" && this.groupID === '' ? 0 : this.groupID;\n return Repository.userFetch(this.courseID, gts).then((r) => r.users);\n }\n}\n"],"names":["User","UserSearch","constructor","baseUrl","html","js","instance","this","users","getMatchedResults","slice","hasresults","length","searchterm","getSearchTerm","getHTMLElements","searchDropdown","searchInput","removeAttribute","selectAllResultsLink","selectOneLink","userID","url","URL","searchParams","set","toString","fetchDataset","gts","groupID","Repository","userFetch","courseID","then","r"],"mappings":";;;;;;;skCA0BqBA,aAAaC,cAO9BC,YAAYC,sBAEHA,QAAUA,oBAGPA,gBACD,IAAIH,KAAKG,sCAOVC,KAACA,KAADC,GAAOA,UAAY,+BAAiB,qCAAsC,CAC5EC,SAAUC,KAAKD,SACfE,MAAOD,KAAKE,oBAAoBC,MAAM,EAAG,GACzCC,WAAYJ,KAAKE,oBAAoBG,OAAS,EAC9CC,WAAYN,KAAKO,qDAEDP,KAAKQ,kBAAkBC,eAAgBZ,KAAMC,SAE5DY,YAAYC,gBAAgB,yBAOrCC,8BACW,KASXC,cAAcC,cACJC,IAAM,IAAIC,IAAIhB,KAAKJ,gBACzBmB,IAAIE,aAAaC,IAAI,cAAelB,KAAKO,iBACzCQ,IAAIE,aAAaC,IAAI,OAAQ,QAC7BH,IAAIE,aAAaC,IAAI,SAAUJ,QACxBC,IAAII,WAQfC,qBAEUC,IAAgC,iBAAlBrB,KAAKsB,SAA0C,KAAjBtB,KAAKsB,QAAiB,EAAItB,KAAKsB,eAC1EC,WAAWC,UAAUxB,KAAKyB,SAAUJ,KAAKK,MAAMC,GAAMA,EAAE1B"}
+14 -10
View File
@@ -21,7 +21,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import GradeItemSearch from 'core_grades/comboboxsearch/grade';
import Url from 'core/url';
// Define our standard lookups.
const selectors = {
@@ -34,12 +33,18 @@ export default class GradeItems extends GradeItemSearch {
courseID = component.querySelector(selectors.courseid).dataset.courseid;
constructor() {
/**
* Construct the class.
*
* @param {string} baseUrl The base URL for the page.
*/
constructor(baseUrl) {
super();
this.baseUrl = baseUrl;
}
static init() {
return new GradeItems();
static init(baseUrl) {
return new GradeItems(baseUrl);
}
/**
@@ -49,11 +54,10 @@ export default class GradeItems extends GradeItemSearch {
* @returns {string|*}
*/
selectOneLink(gradeID) {
return Url.relativeUrl('/grade/report/singleview/index.php', {
id: this.courseID,
gradesearchvalue: this.getSearchTerm(),
item: 'grade',
itemid: gradeID,
}, false);
const url = new URL(this.baseUrl);
url.searchParams.set('gradesearchvalue', this.getSearchTerm());
url.searchParams.set('item', 'grade');
url.searchParams.set('itemid', gradeID);
return url.toString();
}
}
+14 -10
View File
@@ -21,18 +21,23 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import UserSearch from 'core_user/comboboxsearch/user';
import Url from 'core/url';
import {renderForPromise, replaceNodeContents} from 'core/templates';
import * as Repository from 'core_grades/searchwidget/repository';
export default class User extends UserSearch {
constructor() {
/**
* Construct the class.
*
* @param {string} baseUrl The base URL for the page.
*/
constructor(baseUrl) {
super();
this.baseUrl = baseUrl;
}
static init() {
return new User();
static init(baseUrl) {
return new User(baseUrl);
}
/**
@@ -65,12 +70,11 @@ export default class User extends UserSearch {
* @returns {string|*}
*/
selectOneLink(userID) {
return Url.relativeUrl('/grade/report/singleview/index.php', {
id: this.courseID,
searchvalue: this.getSearchTerm(),
item: 'user',
userid: userID,
}, false);
const url = new URL(this.baseUrl);
url.searchParams.set('searchvalue', this.getSearchTerm());
url.searchParams.set('item', 'user');
url.searchParams.set('userid', userID);
return url.toString();
}
/**
+3 -3
View File
@@ -164,18 +164,18 @@ if ($PAGE->user_allowed_editing() && !$PAGE->theme->haseditswitch) {
$reportname = $report->screen->heading();
$baseurl = new moodle_url('/grade/report/singleview/index.php', ['id' => $courseid, 'item' => $itemtype]);
if ($itemtype == 'user' || $itemtype == 'user_select') {
$PAGE->requires->js_call_amd('gradereport_singleview/user', 'init');
$PAGE->requires->js_call_amd('gradereport_singleview/user', 'init', [$baseurl->out(false)]);
$actionbar = new \gradereport_singleview\output\action_bar($context, $report, 'user');
} else if ($itemtype == 'grade' || $itemtype == 'grade_select') {
$PAGE->requires->js_call_amd('gradereport_singleview/grade', 'init');
$PAGE->requires->js_call_amd('gradereport_singleview/grade', 'init', [$baseurl->out(false)]);
$actionbar = new \gradereport_singleview\output\action_bar($context, $report, 'grade');
} else {
$actionbar = new \core_grades\output\general_action_bar($context, new moodle_url('/grade/report/singleview/index.php',
['id' => $courseid]), 'report', 'singleview');
}
if ($course->groupmode && $itemtype !== 'select') {
$baseurl = new moodle_url('/grade/report/singleview/index.php', ['id' => $courseid, 'item' => $itemtype]);
$PAGE->requires->js_call_amd('core_course/actionbar/group', 'init', [$baseurl->out(false)]);
}
+13 -25
View File
@@ -45,36 +45,24 @@ class gradereport_singleview_renderer extends plugin_renderer_base {
* @return string The raw HTML to render.
*/
public function users_selector(object $course, ?int $userid = null, ?int $groupid = null): string {
$actionbarrenderer = $this->page->get_renderer('core_course', 'actionbar');
$resetlink = new moodle_url('/grade/report/singleview/index.php', ['id' => $course->id, 'group' => $groupid ?? 0]);
$submitteduserid = optional_param('userid', '', PARAM_INT);
$usersearch = '';
if ($submitteduserid) {
$user = core_user::get_user($submitteduserid);
$currentvalue = fullname($user);
} else {
$currentvalue = '';
if ($userid) {
$user = core_user::get_user($userid);
$usersearch = fullname($user);
}
$data = [
'currentvalue' => $currentvalue,
'courseid' => $course->id,
'instance' => rand(),
'group' => $groupid ?? 0,
'resetlink' => $resetlink->out(false),
'name' => 'userid',
'value' => $submitteduserid ?? '',
];
$dropdown = new comboboxsearch(
true,
$this->render_from_template('core_user/comboboxsearch/user_selector', $data),
null,
'user-search d-flex',
null,
'usersearchdropdown overflow-auto',
null,
false,
return $actionbarrenderer->render(
new \core_course\output\actionbar\user_selector(
course: $course,
resetlink: $resetlink,
userid: $userid,
groupid: $groupid,
usersearch: $usersearch
)
);
return $this->render_from_template($dropdown->get_template(), $dropdown->export_for_template($this));
}
/**
@@ -22,13 +22,13 @@ Feature: Given we have opted to search for a grade item, Lets find and search th
Scenario: A teacher can search for and find a grade item to view
Given I click on "Grade items" "link" in the ".page-toggler" "css_element"
And I click on ".gradesearchwidget" "css_element"
When I confirm "Test assignment one" in "grade" search within the gradebook widget exists
And I confirm "Test assignment two" in "grade" search within the gradebook widget exists
When I confirm "Test assignment one" exists in the "Search items" search combo box
And I confirm "Test assignment two" exists in the "Search items" search combo box
Then I set the field "Search items" to "two"
And I wait until "Test assignment one" "option_role" does not exist
And I confirm "Test assignment one" in "grade" search within the gradebook widget does not exist
And I confirm "Test assignment two" in "grade" search within the gradebook widget exists
And I click on "Test assignment two" in the "grade" search widget
And I confirm "Test assignment one" does not exist in the "Search items" search combo box
And I confirm "Test assignment two" exists in the "Search items" search combo box
And I click on "Test assignment two" in the "Search items" search combo box
# The search input remains in the field on reload this is in keeping with other search implementations.
And I click on ".gradesearchwidget" "css_element"
And the field "Search items" matches value "two"
@@ -20,7 +20,7 @@ Feature: Given we land on the index page, select what type of report we wish to
Given I am on the "Course 1" "grades > Single view > View" page logged in as "teacher1"
And I click on "Grade items" "link" in the ".page-toggler" "css_element"
And "Search users" "field" should not exist
And I confirm "Test assignment one" in "grade" search within the gradebook widget exists
And I confirm "Test assignment one" exists in the "Search items" search combo box
When I click on "Users" "link" in the ".page-toggler" "css_element"
Then "Search users" "field" should exist
And "Select a grade item" "combobox" should not exist
@@ -60,7 +60,7 @@ Feature: We can use Single view
Scenario: I can update grades, add feedback and exclude grades.
Given I navigate to "View > Single view" in the course gradebook
And I click on "Users" "link" in the ".page-toggler" "css_element"
And I click on "Student" in the "user" search widget
And I click on "Student" in the "Search users" search combo box
And I turn editing mode on
And I set the field "Override for Test assignment one" to "1"
When I set the following fields to these values:
@@ -88,7 +88,7 @@ Feature: We can use Single view
Then I should see "Grades were set for 2 items"
And the field "Grade for Ann, Jill, Grainne, Beauchamp" matches value "12.05"
And the field "Exclude for Jane, Nina, Niamh, Cholmondely" matches value "1"
And I click on "new grade item 1" in the "grade" search widget
And I click on "new grade item 1" in the "Search items" search combo box
And I set the field "Grade for Ann, Jill, Grainne, Beauchamp" to "Very good"
And I press "Save"
Then I should see "Grades were set for 1 items"
@@ -97,7 +97,7 @@ Feature: We can use Single view
| Ann, Jill, Grainne, Beauchamp | Very good |
And I am on the "Course 1" "grades > Single view > View" page logged in as "teacher2"
And I click on "Users" "link" in the ".page-toggler" "css_element"
And I click on "Student" in the "user" search widget
And I click on "Student" in the "Search users" search combo box
And I turn editing mode on
And the "Exclude for Test assignment one" "checkbox" should be disabled
And the "Override for Test assignment one" "checkbox" should be enabled
@@ -157,9 +157,9 @@ Feature: We can use Single view
And I open the action menu in "Test assignment four" "table_row"
And I choose "Show all grades" in the open action menu
Then I should see "Test assignment four"
And I click on "Test assignment three" in the "grade" search widget
And I click on "Test assignment three" in the "Search items" search combo box
Then I should see "Test assignment three"
And I click on "Test assignment four" in the "grade" search widget
And I click on "Test assignment four" in the "Search items" search combo box
Then I should see "Test assignment four"
Scenario: Activities are clickable only when it has a valid activity page.
@@ -181,7 +181,7 @@ Feature: We can use Single view
Scenario: Teacher sees his last viewed user report when navigating back to the gradebook singleview report.
Given I navigate to "View > Single view" in the course gradebook
And I click on "Gronya,Beecham" in the "user" search widget
And I click on "Gronya,Beecham" in the "Search users" search combo box
And I should see "Gronya,Beecham" in the "region-main" "region"
When I am on the "Course 1" "grades > Single view > View" page
Then I should not see "Search for a user to view all their grades" in the "region-main" "region"
@@ -192,7 +192,7 @@ Feature: We can use Single view
Scenario: Teacher sees his last viewed grade item report when navigating back to the gradebook singleview report.
Given I navigate to "View > Single view" in the course gradebook
And I click on "Grade items" "link"
And I click on "Test assignment one" in the "grade" search widget
And I click on "Test assignment one" in the "Search items" search combo box
And I should see "Test assignment one" in the "region-main" "region"
When I am on the "Course 1" "grades > Single view > View" page
Then I should not see "Select a grade item above" in the "region-main" "region"
@@ -212,9 +212,9 @@ Feature: We can use Single view
And I set the field "Group mode" to "Visible groups"
And I press "Save and display"
And I navigate to "View > Single view" in the course gradebook
And I click on "Nee,Chumlee" in the "user" search widget
And I click on "Nee,Chumlee" in the "Search users" search combo box
And I navigate to "View > Grader report" in the course gradebook
And I click on "Group 1" in the "group" search widget
And I click on "Group 1" in the "Search groups" search combo box
When I navigate to "View > Single view" in the course gradebook
Then I should see "Nee,Chumlee" in the "region-main" "region"
And I should not see "Search for a user to view all their grades" in the "region-main" "region"
@@ -231,16 +231,16 @@ Feature: We can use Single view
And I set the field "Group mode" to "Visible groups"
And I press "Save and display"
And I navigate to "View > Single view" in the course gradebook
And I click on "Gronya,Beecham" in the "user" search widget
And I click on "Gronya,Beecham" in the "Search users" search combo box
And I navigate to "View > Grader report" in the course gradebook
And I click on "Group 1" in the "group" search widget
And I click on "Group 1" in the "Search groups" search combo box
When I navigate to "View > Single view" in the course gradebook
Then I should see "Search for a user to view all their grades" in the "region-main" "region"
And I should not see "Gronya,Beecham" in the "region-main" "region"
Scenario: Teacher does not see his last viewed user report if that user is no longer enrolled in the course.
Given I navigate to "View > Single view" in the course gradebook
And I click on "Gronya,Beecham" in the "user" search widget
And I click on "Gronya,Beecham" in the "Search users" search combo box
And I navigate to course participants
And I click on "Unenrol" "icon" in the "Gronya,Beecham" "table_row"
And I click on "Unenrol" "button" in the "Unenrol" "dialogue"
@@ -251,7 +251,7 @@ Feature: We can use Single view
Scenario: Teacher does not see his last viewed grade item report if the item no longer exists in the course.
Given I navigate to "View > Single view" in the course gradebook
And I click on "Grade items" "link"
And I click on "Test assignment four" in the "grade" search widget
And I click on "Test assignment four" in the "Search items" search combo box
And I am on "Course 1" course homepage with editing mode on
And I delete "Test assignment four" activity
And I run all adhoc tasks
@@ -37,8 +37,8 @@ Feature: Within the singleview report, a teacher can search for users.
Given I should see "Search users"
And I should see "Search for a user to view all their grades"
When I set the field "Search users" to "Turtle"
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget does not exist
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
And I confirm "User Example" does not exist in the "Search users" search combo box
And I click on "Turtle Manatee" "list_item"
# Business case: This will trigger a page reload and can not dynamically update the table.
And I wait until the page is ready
@@ -55,7 +55,7 @@ Feature: Within the singleview report, a teacher can search for users.
Scenario: A teacher can search the single view report to find specified users
# Case: Standard search.
Given I click on "Dummy" in the "user" search widget
Given I click on "Dummy" in the "Search users" search combo box
And "Dummy User" "heading" should exist
And "Teacher 1" "heading" should not exist
And "Student 1" "heading" should not exist
@@ -77,14 +77,14 @@ Feature: Within the singleview report, a teacher can search for users.
# Case: Multiple users found and select only one result.
Then I set the field "Search users" to "User"
And I wait until "Dummy User" "option_role" exists
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget does not exist
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" does not exist in the "Search users" search combo box
# Check if the matched field names (by lines) includes some identifiable info to help differentiate similar users.
And I confirm "User (student2@example.com)" in "user" search within the gradebook widget exists
And I confirm "User (student3@example.com)" in "user" search within the gradebook widget exists
And I confirm "User (student4@example.com)" in "user" search within the gradebook widget exists
And I confirm "User (student2@example.com)" exists in the "Search users" search combo box
And I confirm "User (student3@example.com)" exists in the "Search users" search combo box
And I confirm "User (student4@example.com)" exists in the "Search users" search combo box
And I click on "Dummy User" "list_item"
And I wait until the page is ready
And "Dummy User" "heading" should exist
@@ -101,7 +101,7 @@ Feature: Within the singleview report, a teacher can search for users.
And I wait until "No results for \"a\"" "text" exists
Scenario: A teacher can quickly tell that a search is active on the current table
Given I click on "Turtle" in the "user" search widget
Given I click on "Turtle" in the "Search users" search combo box
And I wait until the page is ready
# The search input remains in the field on reload this is in keeping with other search implementations.
When the field "Search users" matches value "Turtle Manatee"
@@ -118,55 +118,55 @@ Feature: Within the singleview report, a teacher can search for users.
And I set the field "Search users" to "@example.com"
And I wait until "Dummy User" "list_item" exists
# Note: All learners match this email & showing emails is current default.
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the country field.
When I set the field "Search users" to "JP"
And I wait until "Dummy User" "list_item" exists
And I wait until "Turtle Manatee" "list_item" does not exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
# Search on the city field.
And I set the field "Search users" to "Hanoi"
And I wait until "User Test" "list_item" does not exist
Then I confirm "Student 1" in "user" search within the gradebook widget exists
Then I confirm "Student 1" exists in the "Search users" search combo box
# Search on the institution field.
And I set the field "Search users" to "ABCD"
And I wait until "Dummy User" "list_item" exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the department field.
And I set the field "Search users" to "ABC3"
And I wait until "User Example" "list_item" does not exist
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the phone1 field.
And I set the field "Search users" to "4365899871"
And I wait until "User Test" "list_item" does not exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
# Search on the phone2 field.
And I set the field "Search users" to "2149871323"
And I wait until "Dummy User" "list_item" does not exist
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "User Test" exists in the "Search users" search combo box
# Search on the institution field then press enter to show the record set.
And I set the field "Search users" to "ABC"
And "Turtle Manatee" "list_item" should exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I press the down key
And I press the enter key
And I wait until the page is ready
@@ -219,4 +219,4 @@ Feature: Within the singleview report, a teacher can search for users.
And I press the tab key
And the focused element is "Clear search input" "button" in the ".user-search" "css_element"
And I press the enter key
And I confirm "Turtle Manatee" in "user" search within the gradebook widget does not exist
And I confirm "Turtle Manatee" does not exist in the "Search users" search combo box
+2 -2
View File
@@ -1,10 +1,10 @@
define("gradereport_user/user",["exports","core_user/comboboxsearch/user","core/url","core/templates","core_grades/searchwidget/repository"],(function(_exports,_user,_url,_templates,Repository){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
define("gradereport_user/user",["exports","core_user/comboboxsearch/user","core/templates","core_grades/searchwidget/repository"],(function(_exports,_user,_templates,Repository){var obj;
/**
* Allow the user to search for learners within the user report.
*
* @module gradereport_user/user
* @copyright 2023 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_user=_interopRequireDefault(_user),_url=_interopRequireDefault(_url),Repository=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Repository);class User extends _user.default{constructor(){super()}static init(){return new User}async renderDropdown(){const{html:html,js:js}=await(0,_templates.renderForPromise)("core_user/comboboxsearch/resultset",{users:this.getMatchedResults().slice(0,5),hasresults:this.getMatchedResults().length>0,instance:this.instance,matches:this.getDatasetSize(),searchterm:this.getSearchTerm(),selectall:this.selectAllResultsLink()});(0,_templates.replaceNodeContents)(this.getHTMLElements().searchDropdown,html,js),this.searchInput.removeAttribute("aria-activedescendant")}selectAllResultsLink(){return _url.default.relativeUrl("/grade/report/user/index.php",{id:this.courseID,userid:0,searchvalue:this.getSearchTerm()},!1)}selectOneLink(userID){return _url.default.relativeUrl("/grade/report/user/index.php",{id:this.courseID,searchvalue:this.getSearchTerm(),userid:userID},!1)}fetchDataset(){const gts="string"==typeof this.groupID&&""===this.groupID?0:this.groupID;return Repository.userFetch(this.courseID,gts).then((r=>r.users))}}return _exports.default=User,_exports.default}));
*/function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_user=(obj=_user)&&obj.__esModule?obj:{default:obj},Repository=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Repository);class User extends _user.default{constructor(baseUrl){super(),this.baseUrl=baseUrl}static init(baseUrl){return new User(baseUrl)}async renderDropdown(){const{html:html,js:js}=await(0,_templates.renderForPromise)("core_user/comboboxsearch/resultset",{users:this.getMatchedResults().slice(0,5),hasresults:this.getMatchedResults().length>0,instance:this.instance,matches:this.getDatasetSize(),searchterm:this.getSearchTerm(),selectall:this.selectAllResultsLink()});(0,_templates.replaceNodeContents)(this.getHTMLElements().searchDropdown,html,js),this.searchInput.removeAttribute("aria-activedescendant")}selectAllResultsLink(){const url=new URL(this.baseUrl);return url.searchParams.set("userid",0),url.searchParams.set("searchvalue",this.getSearchTerm()),url.toString()}selectOneLink(userID){const url=new URL(this.baseUrl);return url.searchParams.set("userid",userID),url.searchParams.set("searchvalue",this.getSearchTerm()),url.toString()}fetchDataset(){const gts="string"==typeof this.groupID&&""===this.groupID?0:this.groupID;return Repository.userFetch(this.courseID,gts).then((r=>r.users))}}return _exports.default=User,_exports.default}));
//# sourceMappingURL=user.min.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"user.min.js","sources":["../src/user.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Allow the user to search for learners within the user report.\n *\n * @module gradereport_user/user\n * @copyright 2023 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport UserSearch from 'core_user/comboboxsearch/user';\nimport Url from 'core/url';\nimport {renderForPromise, replaceNodeContents} from 'core/templates';\nimport * as Repository from 'core_grades/searchwidget/repository';\n\nexport default class User extends UserSearch {\n\n constructor() {\n super();\n }\n\n static init() {\n return new User();\n }\n\n /**\n * Build the content then replace the node.\n */\n async renderDropdown() {\n const {html, js} = await renderForPromise('core_user/comboboxsearch/resultset', {\n users: this.getMatchedResults().slice(0, 5),\n hasresults: this.getMatchedResults().length > 0,\n instance: this.instance,\n matches: this.getDatasetSize(),\n searchterm: this.getSearchTerm(),\n selectall: this.selectAllResultsLink(),\n });\n replaceNodeContents(this.getHTMLElements().searchDropdown, html, js);\n // Remove aria-activedescendant when the available options change.\n this.searchInput.removeAttribute('aria-activedescendant');\n }\n\n /**\n * Build up the view all link.\n *\n * @returns {string|*}\n */\n selectAllResultsLink() {\n return Url.relativeUrl('/grade/report/user/index.php', {\n id: this.courseID,\n userid: 0,\n searchvalue: this.getSearchTerm()\n }, false);\n }\n\n /**\n * Build up the link that is dedicated to a particular result.\n *\n * @param {Number} userID The ID of the user selected.\n * @returns {string|*}\n */\n selectOneLink(userID) {\n return Url.relativeUrl('/grade/report/user/index.php', {\n id: this.courseID,\n searchvalue: this.getSearchTerm(),\n userid: userID,\n }, false);\n }\n\n /**\n * Get the data we will be searching against in this component.\n *\n * @returns {Promise<*>}\n */\n fetchDataset() {\n // Small typing checks as sometimes groups don't exist therefore the element returns a empty string.\n const gts = typeof (this.groupID) === \"string\" && this.groupID === '' ? 0 : this.groupID;\n return Repository.userFetch(this.courseID, gts).then((r) => r.users);\n }\n}\n"],"names":["User","UserSearch","constructor","html","js","users","this","getMatchedResults","slice","hasresults","length","instance","matches","getDatasetSize","searchterm","getSearchTerm","selectall","selectAllResultsLink","getHTMLElements","searchDropdown","searchInput","removeAttribute","Url","relativeUrl","id","courseID","userid","searchvalue","selectOneLink","userID","fetchDataset","gts","groupID","Repository","userFetch","then","r"],"mappings":";;;;;;;q0BA2BqBA,aAAaC,cAE9BC,2CAKW,IAAIF,kCAOLG,KAACA,KAADC,GAAOA,UAAY,+BAAiB,qCAAsC,CAC5EC,MAAOC,KAAKC,oBAAoBC,MAAM,EAAG,GACzCC,WAAYH,KAAKC,oBAAoBG,OAAS,EAC9CC,SAAUL,KAAKK,SACfC,QAASN,KAAKO,iBACdC,WAAYR,KAAKS,gBACjBC,UAAWV,KAAKW,4DAEAX,KAAKY,kBAAkBC,eAAgBhB,KAAMC,SAE5DgB,YAAYC,gBAAgB,yBAQrCJ,8BACWK,aAAIC,YAAY,+BAAgC,CACnDC,GAAIlB,KAAKmB,SACTC,OAAQ,EACRC,YAAarB,KAAKS,kBACnB,GASPa,cAAcC,eACHP,aAAIC,YAAY,+BAAgC,CACnDC,GAAIlB,KAAKmB,SACTE,YAAarB,KAAKS,gBAClBW,OAAQG,SACT,GAQPC,qBAEUC,IAAgC,iBAAlBzB,KAAK0B,SAA0C,KAAjB1B,KAAK0B,QAAiB,EAAI1B,KAAK0B,eAC1EC,WAAWC,UAAU5B,KAAKmB,SAAUM,KAAKI,MAAMC,GAAMA,EAAE/B"}
{"version":3,"file":"user.min.js","sources":["../src/user.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Allow the user to search for learners within the user report.\n *\n * @module gradereport_user/user\n * @copyright 2023 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport UserSearch from 'core_user/comboboxsearch/user';\nimport {renderForPromise, replaceNodeContents} from 'core/templates';\nimport * as Repository from 'core_grades/searchwidget/repository';\n\nexport default class User extends UserSearch {\n\n /**\n * Construct the class.\n *\n * @param {string} baseUrl The base URL for the page.\n */\n constructor(baseUrl) {\n super();\n this.baseUrl = baseUrl;\n }\n\n static init(baseUrl) {\n return new User(baseUrl);\n }\n\n /**\n * Build the content then replace the node.\n */\n async renderDropdown() {\n const {html, js} = await renderForPromise('core_user/comboboxsearch/resultset', {\n users: this.getMatchedResults().slice(0, 5),\n hasresults: this.getMatchedResults().length > 0,\n instance: this.instance,\n matches: this.getDatasetSize(),\n searchterm: this.getSearchTerm(),\n selectall: this.selectAllResultsLink(),\n });\n replaceNodeContents(this.getHTMLElements().searchDropdown, html, js);\n // Remove aria-activedescendant when the available options change.\n this.searchInput.removeAttribute('aria-activedescendant');\n }\n\n /**\n * Build up the view all link.\n *\n * @returns {string|*}\n */\n selectAllResultsLink() {\n const url = new URL(this.baseUrl);\n url.searchParams.set('userid', 0);\n url.searchParams.set('searchvalue', this.getSearchTerm());\n return url.toString();\n }\n\n /**\n * Build up the link that is dedicated to a particular result.\n *\n * @param {Number} userID The ID of the user selected.\n * @returns {string|*}\n */\n selectOneLink(userID) {\n const url = new URL(this.baseUrl);\n url.searchParams.set('userid', userID);\n url.searchParams.set('searchvalue', this.getSearchTerm());\n return url.toString();\n }\n\n /**\n * Get the data we will be searching against in this component.\n *\n * @returns {Promise<*>}\n */\n fetchDataset() {\n // Small typing checks as sometimes groups don't exist therefore the element returns a empty string.\n const gts = typeof (this.groupID) === \"string\" && this.groupID === '' ? 0 : this.groupID;\n return Repository.userFetch(this.courseID, gts).then((r) => r.users);\n }\n}\n"],"names":["User","UserSearch","constructor","baseUrl","html","js","users","this","getMatchedResults","slice","hasresults","length","instance","matches","getDatasetSize","searchterm","getSearchTerm","selectall","selectAllResultsLink","getHTMLElements","searchDropdown","searchInput","removeAttribute","url","URL","searchParams","set","toString","selectOneLink","userID","fetchDataset","gts","groupID","Repository","userFetch","courseID","then","r"],"mappings":";;;;;;;skCA0BqBA,aAAaC,cAO9BC,YAAYC,sBAEHA,QAAUA,oBAGPA,gBACD,IAAIH,KAAKG,sCAOVC,KAACA,KAADC,GAAOA,UAAY,+BAAiB,qCAAsC,CAC5EC,MAAOC,KAAKC,oBAAoBC,MAAM,EAAG,GACzCC,WAAYH,KAAKC,oBAAoBG,OAAS,EAC9CC,SAAUL,KAAKK,SACfC,QAASN,KAAKO,iBACdC,WAAYR,KAAKS,gBACjBC,UAAWV,KAAKW,4DAEAX,KAAKY,kBAAkBC,eAAgBhB,KAAMC,SAE5DgB,YAAYC,gBAAgB,yBAQrCJ,6BACUK,IAAM,IAAIC,IAAIjB,KAAKJ,gBACzBoB,IAAIE,aAAaC,IAAI,SAAU,GAC/BH,IAAIE,aAAaC,IAAI,cAAenB,KAAKS,iBAClCO,IAAII,WASfC,cAAcC,cACJN,IAAM,IAAIC,IAAIjB,KAAKJ,gBACzBoB,IAAIE,aAAaC,IAAI,SAAUG,QAC/BN,IAAIE,aAAaC,IAAI,cAAenB,KAAKS,iBAClCO,IAAII,WAQfG,qBAEUC,IAAgC,iBAAlBxB,KAAKyB,SAA0C,KAAjBzB,KAAKyB,QAAiB,EAAIzB,KAAKyB,eAC1EC,WAAWC,UAAU3B,KAAK4B,SAAUJ,KAAKK,MAAMC,GAAMA,EAAE/B"}
+17 -14
View File
@@ -21,18 +21,23 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import UserSearch from 'core_user/comboboxsearch/user';
import Url from 'core/url';
import {renderForPromise, replaceNodeContents} from 'core/templates';
import * as Repository from 'core_grades/searchwidget/repository';
export default class User extends UserSearch {
constructor() {
/**
* Construct the class.
*
* @param {string} baseUrl The base URL for the page.
*/
constructor(baseUrl) {
super();
this.baseUrl = baseUrl;
}
static init() {
return new User();
static init(baseUrl) {
return new User(baseUrl);
}
/**
@@ -58,11 +63,10 @@ export default class User extends UserSearch {
* @returns {string|*}
*/
selectAllResultsLink() {
return Url.relativeUrl('/grade/report/user/index.php', {
id: this.courseID,
userid: 0,
searchvalue: this.getSearchTerm()
}, false);
const url = new URL(this.baseUrl);
url.searchParams.set('userid', 0);
url.searchParams.set('searchvalue', this.getSearchTerm());
return url.toString();
}
/**
@@ -72,11 +76,10 @@ export default class User extends UserSearch {
* @returns {string|*}
*/
selectOneLink(userID) {
return Url.relativeUrl('/grade/report/user/index.php', {
id: this.courseID,
searchvalue: this.getSearchTerm(),
userid: userID,
}, false);
const url = new URL(this.baseUrl);
url.searchParams.set('userid', userID);
url.searchParams.set('searchvalue', this.getSearchTerm());
return url.toString();
}
/**
@@ -37,6 +37,9 @@ class action_bar extends \core_grades\output\action_bar {
/** @var int|null $currentgroupid The user report view mode. */
protected $currentgroupid;
/** @var string $usersearch String to search matching users. */
protected $usersearch;
/**
* The class constructor.
*
@@ -44,12 +47,20 @@ class action_bar extends \core_grades\output\action_bar {
* @param int $userview The user report view mode.
* @param int|null $userid The user ID or 0 if displaying all users.
* @param int|null $currentgroupid The ID of the current group.
* @param string $usersearch String to search matching user.
*/
public function __construct(\context $context, int $userview, ?int $userid = null, ?int $currentgroupid = null) {
public function __construct(
\context $context,
int $userview,
?int $userid = null,
?int $currentgroupid = null,
string $usersearch = ''
) {
parent::__construct($context);
$this->userview = $userview;
$this->userid = $userid;
$this->currentgroupid = $currentgroupid;
$this->usersearch = $usersearch;
}
/**
@@ -88,7 +99,12 @@ class action_bar extends \core_grades\output\action_bar {
}
$data['userselector'] = [
'courseid' => $courseid,
'content' => $userreportrenderer->users_selector(get_course($courseid), $this->userid, $this->currentgroupid)
'content' => $userreportrenderer->users_selector(
course: get_course($courseid),
userid: $this->userid,
groupid: $this->currentgroupid,
usersearch: $this->usersearch
),
];
// Do not output the 'view mode' selector when in zero state or when the current user is viewing its own report.
+1
View File
@@ -28,6 +28,7 @@ require_once $CFG->dirroot.'/grade/lib.php';
require_once $CFG->dirroot.'/grade/report/user/lib.php';
$courseid = required_param('id', PARAM_INT);
// 0 - view all reports. null - view own report. non-zero and non-null - view other user report.
$userid = optional_param('userid', null, PARAM_INT);
$userview = optional_param('userview', 0, PARAM_INT);
+12 -31
View File
@@ -88,42 +88,23 @@ class gradereport_user_renderer extends plugin_renderer_base {
* @param object $course The course object.
* @param int|null $userid The user ID.
* @param int|null $groupid The group ID.
* @param string $usersearch Search string.
* @return string The raw HTML to render.
* @throws coding_exception
*/
public function users_selector(object $course, ?int $userid = null, ?int $groupid = null): string {
public function users_selector(object $course, ?int $userid = null, ?int $groupid = null, string $usersearch = ''): string {
$actionbarrenderer = $this->page->get_renderer('core_course', 'actionbar');
$resetlink = new moodle_url('/grade/report/user/index.php', ['id' => $course->id, 'group' => 0]);
$submitteduserid = optional_param('userid', '', PARAM_INT);
if ($submitteduserid) {
$user = core_user::get_user($submitteduserid);
$currentvalue = fullname($user);
} else {
$currentvalue = '';
}
$data = [
'currentvalue' => $currentvalue,
'instance' => rand(),
'resetlink' => $resetlink->out(false),
'name' => 'userid',
'value' => $submitteduserid ?? '',
'courseid' => $course->id,
'group' => $groupid ?? 0,
];
$searchdropdown = new comboboxsearch(
true,
$this->render_from_template('core_user/comboboxsearch/user_selector', $data),
null,
'user-search d-flex',
null,
'usersearchdropdown overflow-auto',
null,
false,
$baseurl = new moodle_url('/grade/report/user/index.php', ['id' => $course->id]);
$this->page->requires->js_call_amd('gradereport_user/user', 'init', [$baseurl->out(false)]);
$userselector = new \core_course\output\actionbar\user_selector(
course: $course,
resetlink: $resetlink,
userid: $userid,
groupid: $groupid,
usersearch: $usersearch
);
$this->page->requires->js_call_amd('gradereport_user/user', 'init');
return $this->render_from_template($searchdropdown->get_template(), $searchdropdown->export_for_template($this));
return $actionbarrenderer->render($userselector);
}
/**
@@ -38,13 +38,13 @@ Feature: Group searching functionality within the user report.
Then ".groupsearchwidget" "css_element" should not exist
Scenario: A teacher can search for and find a group to find a user in
Given I confirm "Tutor group" in "group" search within the gradebook widget exists
And I confirm "Marker group" in "group" search within the gradebook widget exists
Given I confirm "Tutor group" exists in the "Search groups" search combo box
And I confirm "Marker group" exists in the "Search groups" search combo box
When I set the field "Search groups" to "tutor"
And I wait "1" seconds
Then I confirm "Tutor group" in "group" search within the gradebook widget exists
And I confirm "Marker group" in "group" search within the gradebook widget does not exist
And I click on "Tutor group" in the "group" search widget
Then I confirm "Tutor group" exists in the "Search groups" search combo box
And I confirm "Marker group" does not exist in the "Search groups" search combo box
And I click on "Tutor group" in the "Search groups" search combo box
# The search input remains in the field on reload this is in keeping with other search implementations.
And I click on ".groupsearchwidget" "css_element"
And the field "Search groups" matches value "tutor"
@@ -54,22 +54,22 @@ Feature: Group searching functionality within the user report.
Scenario: A teacher can only see the group members in the 'user' search widget after selecting a group option
# Confirm that all users are initially displayed in the 'user' search widget.
Given I set the field "Search users" to "Student"
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Student 2" in "user" search within the gradebook widget exists
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Student 2" exists in the "Search users" search combo box
# Select a particular group from the 'group' search widget.
When I click on "Default group" in the "group" search widget
When I click on "Default group" in the "Search groups" search combo box
# Confirm that only users which are members of the selected group are displayed in the 'user' search widget.
And I set the field "Search users" to "Student"
Then I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Student 2" in "user" search within the gradebook widget does not exist
And I click on "Tutor group" in the "group" search widget
Then I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Student 2" does not exist in the "Search users" search combo box
And I click on "Tutor group" in the "Search groups" search combo box
And I set the field "Search users" to "Student"
And I confirm "Student 1" in "user" search within the gradebook widget does not exist
And I confirm "Student 2" in "user" search within the gradebook widget does not exist
And I click on "All participants" in the "group" search widget
And I confirm "Student 1" does not exist in the "Search users" search combo box
And I confirm "Student 2" does not exist in the "Search users" search combo box
And I click on "All participants" in the "Search groups" search combo box
And I set the field "Search users" to "Student"
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Student 2" in "user" search within the gradebook widget exists
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Student 2" exists in the "Search users" search combo box
@accessibility
Scenario: A teacher can set focus and search using the input with a keyboard
@@ -28,7 +28,7 @@ Feature: User can toggle the visibility of the grade categories within the user
Scenario: A teacher can search for and find a user to view
Given I am on the "Course" "grades > User report > View" page logged in as "teacher1"
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And I should see "Test assignment one" in the "user-grade" "table"
And I should see "Test assignment two" in the "user-grade" "table"
And I should see "Category 1 total" in the "user-grade" "table"
@@ -26,7 +26,7 @@ Feature: Teacher can navigate to the previous or next user report.
And I am on the "Course" "grades > User report > View" page logged in as "teacher1"
Scenario: A teacher can navigate to the next user report
Given I click on "Student 1" in the "user" search widget
Given I click on "Student 1" in the "Search users" search combo box
And "Student 1" "heading" should exist
And ".previous" "css_element" should not exist in the ".user-navigation" "css_element"
And ".next" "css_element" should exist in the ".user-navigation" "css_element"
@@ -44,7 +44,7 @@ Feature: Teacher can navigate to the previous or next user report.
And ".next" "css_element" should not exist in the ".user-navigation" "css_element"
Scenario: A teacher can navigate to the previous user report
Given I click on "Student 3" in the "user" search widget
Given I click on "Student 3" in the "Search users" search combo box
And "Student 3" "heading" should exist
And ".previous" "css_element" should exist in the ".user-navigation" "css_element"
And I should see "Student 2" in the ".previous" "css_element"
@@ -52,7 +52,7 @@ Feature: View the user report as the student will see it
| activity | course | idnumber | name | intro | grade |
| quiz | C1 | q1 | Test quiz one | Submit something! | 100 |
When I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And I should see "Course 1 & '\""
And I should not see "Course 1 &amp; '\""
And I set the field "View report as" to "Myself"
@@ -77,7 +77,7 @@ Feature: View the user report as the student will see it
| activity | course | idnumber | name | intro | grade |
| quiz | C1 | q1 | Test quiz one | Submit something! | 100 |
When I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And I set the field "View report as" to "User"
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
@@ -126,7 +126,7 @@ Feature: View the user report as the student will see it
And I set the field with xpath "//select[@name='report_user_showtotalsifcontainhidden']" to "Show totals excluding hidden items"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
When I click on "Student 1" in the "user" search widget
When I click on "Student 1" in the "Search users" search combo box
And I set the field "View report as" to "User"
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
@@ -163,7 +163,7 @@ Feature: View the user report as the student will see it
And I set the field with xpath "//select[@name='report_user_showtotalsifcontainhidden']" to "Show totals including hidden items"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
When I click on "Student 1" in the "user" search widget
When I click on "Student 1" in the "Search users" search combo box
And I set the field "View report as" to "User"
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
@@ -204,7 +204,7 @@ Feature: View the user report as the student will see it
And I set the field with xpath "//select[@name='report_user_showtotalsifcontainhidden']" to "Show totals excluding hidden items"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
When I click on "Student 1" in the "user" search widget
When I click on "Student 1" in the "Search users" search combo box
And I set the field "View report as" to "User"
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
@@ -38,8 +38,8 @@ Feature: Within the User report, a teacher can search for users.
And I should see "Search for a user to view their report"
When I set the field "Search users" to "Turtle"
And "View all results (5)" "option_role" should exist
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget does not exist
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
And I confirm "User Example" does not exist in the "Search users" search combo box
And I click on "Turtle Manatee" "list_item"
# Business case: This will trigger a page reload and can not dynamically update the table.
And I wait until the page is ready
@@ -56,7 +56,7 @@ Feature: Within the User report, a teacher can search for users.
Scenario: A teacher can search the user report to find specified users
# Case: Standard search.
Given I click on "Dummy" in the "user" search widget
Given I click on "Dummy" in the "Search users" search combo box
And "Dummy User" "heading" should exist
And "Teacher 1" "heading" should not exist
And "Student 1" "heading" should not exist
@@ -77,14 +77,14 @@ Feature: Within the User report, a teacher can search for users.
# Case: Multiple users found and select only one result.
Then I set the field "Search users" to "User"
And "View all results (5)" "option_role" should exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget does not exist
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" does not exist in the "Search users" search combo box
# Check if the matched field names (by lines) includes some identifiable info to help differentiate similar users.
And I confirm "User (student2@example.com)" in "user" search within the gradebook widget exists
And I confirm "User (student3@example.com)" in "user" search within the gradebook widget exists
And I confirm "User (student4@example.com)" in "user" search within the gradebook widget exists
And I confirm "User (student2@example.com)" exists in the "Search users" search combo box
And I confirm "User (student3@example.com)" exists in the "Search users" search combo box
And I confirm "User (student4@example.com)" exists in the "Search users" search combo box
And I click on "Dummy User" "list_item"
And I wait until the page is ready
And "Dummy User" "heading" should exist
@@ -121,7 +121,7 @@ Feature: Within the User report, a teacher can search for users.
And I should see "No results for \"a\""
Scenario: A teacher can quickly tell that a search is active on the current table
When I click on "Turtle" in the "user" search widget
When I click on "Turtle" in the "Search users" search combo box
# The search input should contain the name of the user we have selected, so that it is clear that the result pertains to a specific user.
Then the field "Search users" matches value "Turtle Manatee"
And I wait until "View all results (5)" "link" does not exist
@@ -137,55 +137,55 @@ Feature: Within the User report, a teacher can search for users.
And I set the field "Search users" to "@example.com"
And "View all results (5)" "option_role" should exist
# Note: All learners match this email & showing emails is current default.
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the country field.
When I set the field "Search users" to "JP"
And "View all results (5)" "option_role" should exist
And I wait until "Turtle Manatee" "list_item" does not exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
# Search on the city field.
And I set the field "Search users" to "Hanoi"
And I wait until "User Test" "list_item" does not exist
Then I confirm "Student 1" in "user" search within the gradebook widget exists
Then I confirm "Student 1" exists in the "Search users" search combo box
# Search on the institution field.
And I set the field "Search users" to "ABCD"
And "Dummy User" "list_item" should exist
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the department field.
And I set the field "Search users" to "ABC3"
And I wait until "User Example" "list_item" does not exist
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the phone1 field.
And I set the field "Search users" to "4365899871"
And I wait until "User Test" "list_item" does not exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
# Search on the phone2 field.
And I set the field "Search users" to "2149871323"
And I wait until "Dummy User" "list_item" does not exist
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "User Test" exists in the "Search users" search combo box
# Search on the institution field then press enter to show the record set.
And I set the field "Search users" to "ABC"
And "Turtle Manatee" "list_item" should exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I press the up key
And I press the enter key
And I wait until the page is ready
@@ -25,7 +25,7 @@ Feature: We can use the user report
| student1 | C1 | student |
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
And I should see "Search for a user to view their report" in the "region-main" "region"
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And I should see "Student 1" in the "region-main" "region"
When I am on the "Course 1" "grades > User report > View" page
Then I should not see "Search for a user to view their report" in the "region-main" "region"
@@ -51,9 +51,9 @@ Feature: We can use the user report
| user | group |
| student2 | G1 |
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And I navigate to "View > Grader report" in the course gradebook
And I click on "Group 1" in the "group" search widget
And I click on "Group 1" in the "Search groups" search combo box
When I navigate to "View > User report" in the course gradebook
Then I should see "Student 2" in the "region-main" "region"
And I should not see "Search for a user to view their report" in the "region-main" "region"
@@ -76,9 +76,9 @@ Feature: We can use the user report
| user | group |
| student2 | G1 |
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And I navigate to "View > Grader report" in the course gradebook
And I click on "Group 1" in the "group" search widget
And I click on "Group 1" in the "Search groups" search combo box
When I navigate to "View > User report" in the course gradebook
Then I should see "Search for a user to view their report" in the "region-main" "region"
And I should not see "Student 1" in the "region-main" "region"
@@ -95,7 +95,7 @@ Feature: We can use the user report
| student1 | C1 | student |
| student2 | C1 | student |
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And I should see "Student 1" in the "region-main" "region"
And I navigate to course participants
And I click on "Unenrol" "icon" in the "Student 1" "table_row"
-95
View File
@@ -304,99 +304,4 @@ class behat_grade extends behat_base {
protected function select_in_gradebook_navigation_selector() {
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
}
/**
* We tend to use this series of steps a bit so define em once.
*
* @param string $haystack What are we searching within?
* @param string $needle What are we looking for?
* @param bool $fieldset Do we want to set the search field at the same time?
* @return string
* @throws coding_exception
*/
private function get_dropdown_selector(string $haystack, string $needle, bool $fieldset = true): string {
$this->execute("behat_general::wait_until_the_page_is_ready");
// Set the default field to search and handle any special preamble.
$string = get_string('searchusers', 'core');
$selector = '.usersearchdropdown';
if (strtolower($haystack) === 'group') {
$string = get_string('searchgroups', 'core');
$selector = '.groupsearchdropdown';
$trigger = ".groupsearchwidget";
$node = $this->find("css_element", $selector);
if (!$node->isVisible()) {
$this->execute("behat_general::i_click_on", [$trigger, "css_element"]);
}
} else if (strtolower($haystack) === 'grade') {
$string = get_string('searchitems', 'core');
$selector = '.gradesearchdropdown';
$trigger = ".gradesearchwidget";
$node = $this->find("css_element", $selector);
if (!$node->isVisible()) {
$this->execute("behat_general::i_click_on", [$trigger, "css_element"]);
}
}
if ($fieldset) {
$this->execute("behat_forms::set_field_value", [$string, $needle]);
$this->execute("behat_general::wait_until_exists", [$needle, "list_item"]);
}
return $selector;
}
/**
* Confirm if a value is within the search widget within the gradebook.
*
* Examples:
* - I confirm "User" in "user" search within the gradebook widget exists
* - I confirm "Group" in "group" search within the gradebook widget exists
* - I confirm "Grade item" in "grade" search within the gradebook widget exists
*
* @Given /^I confirm "(?P<needle>(?:[^"]|\\")*)" in "(?P<haystack>(?:[^"]|\\")*)" search within the gradebook widget exists$/
* @param string $needle The value to search for.
* @param string $haystack The type of the search widget.
*/
public function i_confirm_in_search_within_the_gradebook_widget_exists($needle, $haystack) {
$this->execute("behat_general::assert_element_contains_text",
[$needle, $this->get_dropdown_selector($haystack, $needle, false), "css_element"]);
}
/**
* Confirm if a value is not within the search widget within the gradebook.
*
* Examples:
* - I confirm "User" in "user" search within the gradebook widget does not exist
* - I confirm "Group" in "group" search within the gradebook widget does not exist
* - I confirm "Grade item" in "grade" search within the gradebook widget does not exist
*
* @Given /^I confirm "(?P<needle>(?:[^"]|\\")*)" in "(?P<haystack>(?:[^"]|\\")*)" search within the gradebook widget does not exist$/
* @param string $needle The value to search for.
* @param string $haystack The type of the search widget.
*/
public function i_confirm_in_search_within_the_gradebook_widget_does_not_exist($needle, $haystack) {
$this->execute("behat_general::assert_element_not_contains_text",
[$needle, $this->get_dropdown_selector($haystack, $needle, false), "css_element"]);
}
/**
* Clicks on an option from the specified search widget in the current gradebook page.
*
* Examples:
* - I click on "Student" in the "user" search widget
* - I click on "Group" in the "group" search widget
* - I click on "Grade item" in the "grade" search widget
*
* @Given /^I click on "(?P<needle>(?:[^"]|\\")*)" in the "(?P<haystack>(?:[^"]|\\")*)" search widget$/
* @param string $needle The value to search for.
* @param string $haystack The type of the search widget.
*/
public function i_click_on_in_search_widget(string $needle, string $haystack) {
$selector = $this->get_dropdown_selector($haystack, $needle);
$this->execute('behat_general::i_click_on_in_the', [
$needle, "list_item",
$selector, "css_element"
]);
$this->execute("behat_general::i_wait_to_be_redirected");
}
}
@@ -53,4 +53,133 @@ class behat_grade_deprecated extends behat_deprecated_base {
$this->execute('behat_forms::i_set_the_field_to', array($this->escape($fieldstr), $this->escape($feedback)));
}
/**
* Confirm if a value is within the search widget within the gradebook.
*
* Examples:
* - I confirm "User" in "user" search within the gradebook widget exists
* - I confirm "Group" in "group" search within the gradebook widget exists
* - I confirm "Grade item" in "grade" search within the gradebook widget exists
*
* @Given /^I confirm "(?P<needle>(?:[^"]|\\")*)" in "(?P<haystack>(?:[^"]|\\")*)" search within the gradebook widget exists$/
* @param string $needle The value to search for.
* @param string $haystack The type of the search widget.
* @deprecated since 4.5
*/
public function i_confirm_in_search_within_the_gradebook_widget_exists($needle, $haystack) {
$this->deprecated_message('behat_general::i_confirm_in_search_combobox_exists');
$this->execute("behat_general::wait_until_the_page_is_ready");
// Set the default field to search and handle any special preamble.
$selector = '.usersearchdropdown';
if (strtolower($haystack) === 'group') {
$selector = '.groupsearchdropdown';
$trigger = ".groupsearchwidget";
$node = $this->find("css_element", $selector);
if (!$node->isVisible()) {
$this->execute("behat_general::i_click_on", [$trigger, "css_element"]);
}
} else if (strtolower($haystack) === 'grade') {
$selector = '.gradesearchdropdown';
$trigger = ".gradesearchwidget";
$node = $this->find("css_element", $selector);
if (!$node->isVisible()) {
$this->execute("behat_general::i_click_on", [$trigger, "css_element"]);
}
}
$this->execute("behat_general::assert_element_contains_text",
[$needle, $selector, "css_element"]);
}
/**
* Confirm if a value is not within the search widget within the gradebook.
*
* Examples:
* - I confirm "User" in "user" search within the gradebook widget does not exist
* - I confirm "Group" in "group" search within the gradebook widget does not exist
* - I confirm "Grade item" in "grade" search within the gradebook widget does not exist
*
* @Given /^I confirm "(?P<needle>(?:[^"]|\\")*)" in "(?P<haystack>(?:[^"]|\\")*)" search within the gradebook widget does not exist$/
* @param string $needle The value to search for.
* @param string $haystack The type of the search widget.
* @deprecated since 4.5
*/
public function i_confirm_in_search_within_the_gradebook_widget_does_not_exist($needle, $haystack) {
$this->deprecated_message('behat_general::i_confirm_in_search_combobox_does_not_exist');
$this->execute("behat_general::wait_until_the_page_is_ready");
// Set the default field to search and handle any special preamble.
$selector = '.usersearchdropdown';
if (strtolower($haystack) === 'group') {
$selector = '.groupsearchdropdown';
$trigger = ".groupsearchwidget";
$node = $this->find("css_element", $selector);
if (!$node->isVisible()) {
$this->execute("behat_general::i_click_on", [$trigger, "css_element"]);
}
} else if (strtolower($haystack) === 'grade') {
$selector = '.gradesearchdropdown';
$trigger = ".gradesearchwidget";
$node = $this->find("css_element", $selector);
if (!$node->isVisible()) {
$this->execute("behat_general::i_click_on", [$trigger, "css_element"]);
}
}
$this->execute("behat_general::assert_element_not_contains_text",
[$needle, $selector, "css_element"]);
}
/**
* Clicks on an option from the specified search widget in the current gradebook page.
*
* Examples:
* - I click on "Student" in the "user" search widget
* - I click on "Group" in the "group" search widget
* - I click on "Grade item" in the "grade" search widget
*
* @Given /^I click on "(?P<needle>(?:[^"]|\\")*)" in the "(?P<haystack>(?:[^"]|\\")*)" search widget$/
* @param string $needle The value to search for.
* @param string $haystack The type of the search widget.
* @deprecated since 4.5
*/
public function i_click_on_in_search_widget(string $needle, string $haystack) {
$this->deprecated_message('behat_general::i_click_on_in_search_combobox');
$this->execute("behat_general::wait_until_the_page_is_ready");
// Set the default field to search and handle any special preamble.
$string = get_string('searchusers', 'core');
$selector = '.usersearchdropdown';
if (strtolower($haystack) === 'group') {
$string = get_string('searchgroups', 'core');
$selector = '.groupsearchdropdown';
$trigger = ".groupsearchwidget";
$node = $this->find("css_element", $selector);
if (!$node->isVisible()) {
$this->execute("behat_general::i_click_on", [$trigger, "css_element"]);
}
} else if (strtolower($haystack) === 'grade') {
$string = get_string('searchitems', 'core');
$selector = '.gradesearchdropdown';
$trigger = ".gradesearchwidget";
$node = $this->find("css_element", $selector);
if (!$node->isVisible()) {
$this->execute("behat_general::i_click_on", [$trigger, "css_element"]);
}
}
$this->execute("behat_forms::set_field_value", [$string, $needle]);
$this->execute("behat_general::wait_until_exists", [$needle, "list_item"]);
$this->execute('behat_general::i_click_on_in_the', [
$needle, "list_item",
$selector, "css_element",
]);
$this->execute("behat_general::i_wait_to_be_redirected");
}
}
+2 -2
View File
@@ -345,7 +345,7 @@ Feature: We can use calculated grade totals
And I set the field "Show weightings" to "Show"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And I set the field "View report as" to "Myself"
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Contribution to course total |
@@ -542,7 +542,7 @@ Feature: We can use calculated grade totals
And I navigate to "View > Grader report" in the course gradebook
Then I should see "75.00 (16.85 %)" in the ".course" "css_element"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And I set the field "View report as" to "Myself"
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Contribution to course total |
@@ -41,7 +41,7 @@ Feature: Calculated grade items can be used in the gradebook
And I give the grade "75.00" to the user "Student 1" for the grade item "grade item 1"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 75.00 | 0100 | 75.00 % | - |
@@ -71,7 +71,7 @@ Feature: Calculated grade items can be used in the gradebook
And I give the grade "75.00" to the user "Student 1" for the grade item "grade item 1"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 75.00 | 0100 | 75.00 % | - |
@@ -84,13 +84,13 @@ Feature: Calculated grade items can be used in the gradebook
And I give the grade "65.00" to the user "Student 2" for the grade item "grade item 1"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
When I click on "Student 1" in the "user" search widget
When I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 75.00 | 0100 | 75.00 % | - |
| Calc cat total | 100.00 % | 37.50 | 040 | 93.75 % | - |
| Course total | - | 37.50 | 040 | 93.75 % | - |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 65.00 | 0100 | 65.00 % | - |
@@ -101,13 +101,13 @@ Feature: Calculated grade items can be used in the gradebook
| Min and max grades used in calculation | Initial min and max grades |
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 75.00 | 0100 | 75.00 % | - |
| Calc cat total | 100.00 % | 37.50 | 040 | 93.75 % | - |
| Course total | - | 37.50 | 040 | 93.75 % | - |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 65.00 | 0100 | 65.00 % | - |
@@ -137,7 +137,7 @@ Feature: Calculated grade items can be used in the gradebook
And I give the grade "75.00" to the user "Student 1" for the grade item "grade item 1"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
When I click on "Student 1" in the "user" search widget
When I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | 66.67 % | 75.00 | 0100 | 75.00 % | 50.00 % |
@@ -151,13 +151,13 @@ Feature: Calculated grade items can be used in the gradebook
And I give the grade "65.00" to the user "Student 2" for the grade item "grade item 1"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | 71.43 % | 75.00 | 0100 | 75.00 % | 53.57 % |
| calc item | 28.57 % | 37.50 | 040 | 93.75 % | 26.79 % |
| Course total | - | 112.50 | 0140 | 80.36 % | - |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | 71.43 % | 65.00 | 0100 | 65.00 % | 46.43 % |
@@ -42,7 +42,7 @@ Feature: Gradebook calculations for calculated grade items before the fix 201506
And I give the grade "75.00" to the user "Student 1" for the grade item "grade item 1"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 75.00 | 0100 | 75.00 % | - |
@@ -70,7 +70,7 @@ Feature: Gradebook calculations for calculated grade items before the fix 201506
And I give the grade "75.00" to the user "Student 1" for the grade item "grade item 1"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 75.00 | 0100 | 75.00 % | - |
@@ -83,13 +83,13 @@ Feature: Gradebook calculations for calculated grade items before the fix 201506
And I give the grade "65.00" to the user "Student 2" for the grade item "grade item 1"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
When I click on "Student 1" in the "user" search widget
When I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 75.00 | 0100 | 75.00 % | - |
| Calc cat total | 100.00 % | 37.50 | 0100 | 37.50 % | - |
| Course total | - | 37.50 | 0100 | 37.50 % | - |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 65.00 | 0100 | 65.00 % | - |
@@ -100,13 +100,13 @@ Feature: Gradebook calculations for calculated grade items before the fix 201506
| Min and max grades used in calculation | Initial min and max grades |
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 75.00 | 0100 | 75.00 % | - |
| Calc cat total | 100.00 % | 37.50 | 0100 | 37.50 % | - |
| Course total | - | 37.50 | 0100 | 37.50 % | - |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | - | 65.00 | 0100 | 65.00 % | - |
@@ -136,7 +136,7 @@ Feature: Gradebook calculations for calculated grade items before the fix 201506
And I give the grade "75.00" to the user "Student 1" for the grade item "grade item 1"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
When I click on "Student 1" in the "user" search widget
When I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | 50.00 % | 75.00 | 0100 | 75.00 % | 37.50 % |
@@ -150,13 +150,13 @@ Feature: Gradebook calculations for calculated grade items before the fix 201506
And I give the grade "65.00" to the user "Student 2" for the grade item "grade item 1"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | 50.00 % | 75.00 | 0100 | 75.00 % | 37.50 % |
| calc item | 50.00 % | 37.50 | 0100 | 37.50 % | 18.75 % |
| Course total | - | 112.50 | 0200 | 56.25 % | - |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| grade item 1 | 50.00 % | 65.00 | 0100 | 65.00 % | 32.50 % |
@@ -57,7 +57,7 @@ Feature: We can understand the gradebook user report
And I set the following settings for grade item "Course 1" of type "course" on "setup" page:
| Aggregation | Mean of grades |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
# Check the values in the weights column.
Then the following should exist in the "user-grade" table:
@@ -82,7 +82,7 @@ Feature: We can understand the gradebook user report
And I set the following settings for grade item "Sub category" of type "category" on "setup" page:
| Item weight | 1.0 |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
# Check the values in the weights column.
Then the following should exist in the "user-grade" table:
@@ -103,7 +103,7 @@ Feature: We can understand the gradebook user report
And I set the following settings for grade item "Test assignment three" of type "gradeitem" on "setup" page:
| Extra credit | 1 |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
# Check the values in the weights column.
Then the following should exist in the "user-grade" table:
@@ -122,7 +122,7 @@ Feature: We can understand the gradebook user report
And I set the following settings for grade item "Test assignment three" of type "gradeitem" on "setup" page:
| Extra credit weight | 1.0 |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
# Check the values in the weights column.
Then the following should exist in the "user-grade" table:
@@ -139,7 +139,7 @@ Feature: We can understand the gradebook user report
And I set the following settings for grade item "Course 1" of type "course" on "setup" page:
| Aggregation | Median of grades |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
# Check the values in the weights column.
Then the following should exist in the "user-grade" table:
@@ -156,7 +156,7 @@ Feature: We can understand the gradebook user report
And I set the following settings for grade item "Course 1" of type "course" on "setup" page:
| Aggregation | Lowest grade |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
# Check the values in the weights column.
Then the following should exist in the "user-grade" table:
@@ -173,7 +173,7 @@ Feature: We can understand the gradebook user report
And I set the following settings for grade item "Course 1" of type "course" on "setup" page:
| Aggregation | Highest grade |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
# Check the values in the weights column.
Then the following should exist in the "user-grade" table:
@@ -190,7 +190,7 @@ Feature: We can understand the gradebook user report
And I set the following settings for grade item "Course 1" of type "course" on "setup" page:
| Aggregation | Mode of grades |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
# Check the values in the weights column.
Then the following should exist in the "user-grade" table:
@@ -212,7 +212,7 @@ Feature: We can understand the gradebook user report
And I set the following settings for grade item "Test assignment three" of type "gradeitem" on "setup" page:
| aggregationcoef | 1 |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
# Check the values in the weights column.
Then the following should exist in the "user-grade" table:
@@ -231,7 +231,7 @@ Feature: We can understand the gradebook user report
And I set the following settings for grade item "Test assignment three" of type "gradeitem" on "setup" page:
| Extra credit | 1 |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
# Check the values in the weights column.
Then the following should exist in the "user-grade" table:
@@ -60,7 +60,7 @@ Feature: Extra credit contributions are normalised when going out of bounds
And I set the following settings for grade item "Manual item 4" of type "gradeitem" on "setup" page:
| aggregationcoef | 1 |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Contribution to course total |
| Manual item 1 | <m1w> | 80.00 | <m1c> |
@@ -42,11 +42,11 @@ Feature: We can change the maximum and minimum number of points for manual items
| Rescale existing grades | No |
| Maximum grade | 10 |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Contribution to course total |
| Manual item 1 | 100.00 % | 10.00 | 100.00 % |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Contribution to course total |
| Manual item 1 | 100.00 % | 8.00 | 80.00 % |
@@ -58,11 +58,11 @@ Feature: We can change the maximum and minimum number of points for manual items
| Maximum grade | 20 |
And I click on "Save" "button" in the "Edit grade item" "dialogue"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Contribution to course total |
| Manual item 1 | 100.00 % | 20.00 | 100.00 % |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Contribution to course total |
| Manual item 1 | 100.00 % | 16.00 | 80.00 % |
+1 -1
View File
@@ -46,7 +46,7 @@ Feature: Student and teacher's view of aggregated grade items is consistent when
And I set the following settings for grade item "Test assignment four" of type "gradeitem" on "grader" page:
| Hidden | 1 |
And I am on the "Course 1" "grades > User report > View" page
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And I set the field "View report as" to "Myself"
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
@@ -39,7 +39,7 @@ Feature: Hidden grade items should be hidden when grade category is locked, but
Scenario: Hidden grade items in locked category is hidden for teacher
Given I am on the "Course 1" "grades > User report > View" page logged in as teacher1
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
When I set the field "View report as" to "Myself"
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
+2 -2
View File
@@ -63,7 +63,7 @@ Feature: We can use a minimum grade different than zero
And I give the grade "50.00" to the user "Student 2" for the grade item "Manual item 6"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Contribution to course total |
| Manual item 1 | 18.18 % | -25.00 | -4.55 % |
@@ -72,7 +72,7 @@ Feature: We can use a minimum grade different than zero
| Manual item 4 | 66.67 % | -10.00 | -1.82 % |
| Manual item 5 | 50.00 % | 50.00 | 9.09 % |
| Manual item 6 | 50.00 % | 75.00 | 13.64 % |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Contribution to course total |
| Manual item 1 | 18.18 % | 0.00 | 0.00 % |
+8 -8
View File
@@ -72,7 +72,7 @@ Feature: We can choose what min or max grade to use when aggregating grades.
And I give the grade "10.00" to the user "Student 2" for the grade item "MI 3"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| MI 1 | 20.00 % | 75.00 | 0100 | 75.00 % | 15.00 % |
@@ -82,7 +82,7 @@ Feature: We can choose what min or max grade to use when aggregating grades.
| MI 5 | 20.00 % | 100.00 | 0100 | 100.00 % | 20.00 % |
| CAT1 total | 40.00 % | 150.00 | 0200 | 75.00 % | - |
| Course total | - | 350.00 | 0500 | 70.00 % | - |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| MI 1 | 33.33 % | 20.00 | 0100 | 20.00 % | 6.67 % |
@@ -102,7 +102,7 @@ Feature: We can choose what min or max grade to use when aggregating grades.
| Maximum grade | 50.00 |
| Minimum grade | 5.00 |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| MI 1 | 12.50 % | 75.00 | 550 | 100.00 % | 18.75 % |
@@ -112,7 +112,7 @@ Feature: We can choose what min or max grade to use when aggregating grades.
| MI 5 | 25.00 % | 100.00 | 0100 | 100.00 % | 25.00 % |
| CAT1 total | 37.50 % | 150.00 | 0150 | 100.00 % | - |
| Course total | - | 350.00 | 0400 | 87.50 % | - |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| MI 1 | 25.00 % | 20.00 | 550 | 33.33 % | 10.00 % |
@@ -127,12 +127,12 @@ Feature: We can choose what min or max grade to use when aggregating grades.
| Rescale existing grades | No |
| Maximum grade | 200.00 |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| MI 5 | 40.00 % | 150.00 | 0200 | 75.00 % | 30.00 % |
| Course total | - | 400.00 | 0500 | 80.00 % | - |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| MI 5 | 66.67 % | 30.00 | 0200 | 15.00 % | 10.00 % |
@@ -141,7 +141,7 @@ Feature: We can choose what min or max grade to use when aggregating grades.
When I set the field "Min and max grades used in calculation" to "Initial min and max grades"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| MI 1 | 16.67 % | 75.00 | 0100 | 75.00 % | 12.50 % |
@@ -151,7 +151,7 @@ Feature: We can choose what min or max grade to use when aggregating grades.
| MI 5 | 33.33 % | 150.00 | 0200 | 75.00 % | 25.00 % |
| CAT1 total | 33.33 % | 150.00 | 0200 | 75.00 % | - |
| Course total | - | 400.00 | 0600 | 66.67 % | - |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| MI 1 | 25.00 % | 20.00 | 0100 | 20.00 % | 5.00 % |
@@ -40,7 +40,7 @@ Feature: Weights in natural aggregation are adjusted if the items are excluded f
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 28.57 % | 80.00 | 0100 | 80.00 % | 22.86 % |
@@ -61,7 +61,7 @@ Feature: Weights in natural aggregation are adjusted if the items are excluded f
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 66.67 % | 80.00 | 0100 | 80.00 % | 53.33 % |
@@ -80,7 +80,7 @@ Feature: Weights in natural aggregation are adjusted if the items are excluded f
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 0.00 %( Empty ) | - | 0100 | - | 0.00 % |
@@ -107,7 +107,7 @@ Feature: Weights in natural aggregation are adjusted if the items are excluded f
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 0.00 %( Extra credit ) | 80.00 | 0100 | 80.00 % | 0.00 % |
@@ -132,7 +132,7 @@ Feature: Weights in natural aggregation are adjusted if the items are excluded f
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 50.00 % | 80.00 | 0100 | 80.00 % | 40.00 % |
@@ -156,7 +156,7 @@ Feature: Weights in natural aggregation are adjusted if the items are excluded f
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 83.33 % | 80.00 | 0100 | 80.00 % | 66.67 % |
@@ -178,7 +178,7 @@ Feature: Weights in natural aggregation are adjusted if the items are excluded f
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 0.00 %( Empty ) | - | 0100 | - | 0.00 % |
@@ -205,7 +205,7 @@ Feature: Weights in natural aggregation are adjusted if the items are excluded f
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 50.00 % | 80.00 | 0100 | 80.00 % | 40.00 % |
@@ -231,7 +231,7 @@ Feature: Weights in natural aggregation are adjusted if the items are excluded f
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 83.33 % | 80.00 | 0100 | 80.00 % | 66.67 % |
@@ -255,7 +255,7 @@ Feature: Weights in natural aggregation are adjusted if the items are excluded f
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 0.00 %( Empty ) | - | 0100 | - | 0.00 % |
@@ -41,7 +41,7 @@ Feature: Gradebook calculations for extra credit items before the fix 20150619
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 28.57 % | 80.00 | 0100 | 80.00 % | 22.86 % |
@@ -62,7 +62,7 @@ Feature: Gradebook calculations for extra credit items before the fix 20150619
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 66.67 % | 80.00 | 0100 | 80.00 % | 53.33 % |
@@ -81,7 +81,7 @@ Feature: Gradebook calculations for extra credit items before the fix 20150619
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 0.00 %( Empty ) | - | 0100 | - | 0.00 % |
@@ -108,7 +108,7 @@ Feature: Gradebook calculations for extra credit items before the fix 20150619
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 0.00 %( Extra credit ) | 80.00 | 0100 | 80.00 % | 0.00 % |
@@ -133,7 +133,7 @@ Feature: Gradebook calculations for extra credit items before the fix 20150619
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 50.00 % | 80.00 | 0100 | 80.00 % | 40.00 % |
@@ -158,7 +158,7 @@ Feature: Gradebook calculations for extra credit items before the fix 20150619
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 83.33 % | 80.00 | 0100 | 80.00 % | 66.67 % |
@@ -181,7 +181,7 @@ Feature: Gradebook calculations for extra credit items before the fix 20150619
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 0.00 %( Empty ) | - | 0100 | - | 0.00 % |
@@ -208,7 +208,7 @@ Feature: Gradebook calculations for extra credit items before the fix 20150619
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 50.00 % | 80.00 | 0100 | 80.00 % | 40.00 % |
@@ -235,7 +235,7 @@ Feature: Gradebook calculations for extra credit items before the fix 20150619
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 83.33 % | 80.00 | 0100 | 80.00 % | 66.67 % |
@@ -260,7 +260,7 @@ Feature: Gradebook calculations for extra credit items before the fix 20150619
And I give the grade "8.00" to the user "Student 1" for the grade item "Test assignment five (extra)"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 0.00 %( Empty ) | - | 0100 | - | 0.00 % |
+2 -2
View File
@@ -84,7 +84,7 @@ Feature: View gradebook when scales are used
| Range | FA | 0.005.00 | 0.005.00 |
| Overall average | C | 3.00 | 3.00 |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 3" in the "user" search widget
And I click on "Student 3" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | C | FA | 50.00 % | 60.00 % |
@@ -127,7 +127,7 @@ Feature: View gradebook when scales are used
| Range | FA | 1.005.00 | 0.00100.00 |
| Overall average | C | 3.00 | <overallavg> |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 3" in the "user" search widget
And I click on "Student 3" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | C | FA | 50.00 % | <contrib3> |
@@ -44,7 +44,7 @@ Feature: Control the aggregation of the scales
And I set the following settings for grade item "Course 1" of type "course" on "grader" page:
| Aggregation | <aggregation> |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Percentage | Contribution to course total |
| Grade me | 10.00 | 10.00 % | <gradecontrib> |
@@ -55,7 +55,7 @@ Feature: Control the aggregation of the scales
And I set the following administration settings values:
| grade_includescalesinaggregation | 1 |
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Grade | Percentage | Contribution to course total |
| Grade me | 10.00 | 10.00 % | <gradecontrib2> |
@@ -65,13 +65,13 @@ Feature: View gradebook when single item scales are used
| Range | Ace!Ace! | 0.001.00 | 0.001.00 |
| Overall average | Ace! | 1.00 | 1.00 |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Grade | Range | Contribution to course total |
| Test assignment one | Ace! | Ace!Ace! | 100.00 % |
| ENFR Sub category 1 total | 1.00 | 01 | - |
| Course total | 1.00 | 01 | - |
And I click on "Student 2" in the "user" search widget
And I click on "Student 2" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Grade | Range | Contribution to course total |
| Test assignment one | - | Ace!Ace! | - |
@@ -100,7 +100,7 @@ Feature: View gradebook when single item scales are used
| Range | Ace!Ace! | 0.00100.0 | 0.00100.00 |
| Overall average | Ace! | <catavg> | <overallavg> |
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
And the following should exist in the "user-grade" table:
| Grade item | Grade | Range | Contribution to course total |
| Test assignment one | Ace! | Ace!Ace! | <contrib1> |
+95
View File
@@ -22,6 +22,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use core_user\fields;
defined('MOODLE_INTERNAL') || die();
/**
@@ -1489,4 +1491,97 @@ class core_user {
return $initials;
}
/**
* Prepare SQL where clause and associated parameters for any user searching being performed.
* This mostly came from core_user\table\participants_search with some slight modifications four our use case.
*
* @param context $context Context we are in.
* @param string $usersearch Array of field mappings (fieldname => SQL code for the value)
* @return array SQL query data in the format ['where' => '', 'params' => []].
*/
public static function get_users_search_sql(context $context, string $usersearch = ''): array {
global $DB, $USER;
$userfields = fields::for_identity($context, false)->with_userpic();
['mappings' => $mappings] = (array)$userfields->get_sql('u', true);
$userfields = $userfields->get_required_fields();
$canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
$params = [];
$searchkey1 = 'search01';
$searchkey2 = 'search02';
$searchkey3 = 'search03';
$conditions = [];
// Search by fullname.
[$fullname, $fullnameparams] = fields::get_sql_fullname('u', $canviewfullnames);
$conditions[] = $DB->sql_like($fullname, ':' . $searchkey1, false, false);
$params = array_merge($params, $fullnameparams);
// Search by email.
$email = $DB->sql_like('email', ':' . $searchkey2, false, false);
if (!in_array('email', $userfields)) {
$maildisplay = 'maildisplay0';
$userid1 = 'userid01';
// Prevent users who hide their email address from being found by others
// who aren't allowed to see hidden email addresses.
$email = "(". $email ." AND (" .
"u.maildisplay <> :$maildisplay " .
"OR u.id = :$userid1". // Users can always find themselves.
"))";
$params[$maildisplay] = self::MAILDISPLAY_HIDE;
$params[$userid1] = $USER->id;
}
$conditions[] = $email;
// Search by idnumber.
$idnumber = $DB->sql_like('idnumber', ':' . $searchkey3, false, false);
if (!in_array('idnumber', $userfields)) {
$userid2 = 'userid02';
// Users who aren't allowed to see idnumbers should at most find themselves
// when searching for an idnumber.
$idnumber = "(". $idnumber . " AND u.id = :$userid2)";
$params[$userid2] = $USER->id;
}
$conditions[] = $idnumber;
// Search all user identify fields.
$extrasearchfields = fields::get_identity_fields(null, false);
foreach ($extrasearchfields as $fieldindex => $extrasearchfield) {
if (in_array($extrasearchfield, ['email', 'idnumber', 'country'])) {
// Already covered above.
continue;
}
// The param must be short (max 32 characters) so don't include field name.
$param = $searchkey3 . '_ident' . $fieldindex;
$fieldsql = $mappings[$extrasearchfield];
$condition = $DB->sql_like($fieldsql, ':' . $param, false, false);
$params[$param] = "%$usersearch%";
if (!in_array($extrasearchfield, $userfields)) {
// User cannot see this field, but allow match if their own account.
$userid3 = 'userid03_ident' . $fieldindex;
$condition = "(". $condition . " AND u.id = :$userid3)";
$params[$userid3] = $USER->id;
}
$conditions[] = $condition;
}
$where = "(". implode(" OR ", $conditions) .") ";
$params[$searchkey1] = "%$usersearch%";
$params[$searchkey2] = "%$usersearch%";
$params[$searchkey3] = "%$usersearch%";
return [
'where' => $where,
'params' => $params,
];
}
}
+1 -1
View File
@@ -49,7 +49,7 @@
{{#buttonheader}}
<small>{{.}}</small>
{{/buttonheader}}
<div class="{{#parentclasses}}{{.}}{{/parentclasses}} dropdown" data-instance="{{instance}}">
<div class="{{#parentclasses}}{{.}}{{/parentclasses}} dropdown comboboxsearch" data-instance="{{instance}}">
{{#usebutton}}
<div tabindex="0"
+89
View File
@@ -2490,4 +2490,93 @@ EOF;
throw new \Behat\Mink\Exception\ExpectationException('Invalid state for switch: ' . $state, $this->getSession());
}
}
/**
* Helper that returns the dropdown node element within a particular search combo box.
*
* @param string $comboboxname The name (label) of the search combo box element. (e.g. "Search users", "Search groups").
* @param string $itemname The name of the combo box item we are searching for. This is only used if $fieldset is set
* to true.
* @param bool $fieldset Whether to set the search field of the combo box at the same time
* @return NodeElement
* @throws coding_exception
*/
private function get_combobox_dropdown_node(string $comboboxname, string $itemname, bool $fieldset = true): NodeElement {
$this->execute("behat_general::wait_until_the_page_is_ready");
$comboboxxpath = "//div[contains(@class, 'comboboxsearch') and .//span[text()='{$comboboxname}']]";
$dropdowntriggerxpath = $comboboxxpath . "/descendant::div[contains(@class,'dropdown-toggle')]";
$dropdownxpath = $comboboxxpath . "/descendant::div[contains(@class,'dropdown-menu')]";
$dropdown = $this->find("xpath_element", $dropdownxpath);
// If the dropdown is not visible, open it. Also, ensure that a dropdown trigger element exists.
if ($this->getSession()->getPage()->find('xpath', $dropdowntriggerxpath) && !$dropdown->isVisible()) {
$this->execute("behat_general::i_click_on", [$dropdowntriggerxpath, "xpath_element"]);
}
if ($fieldset) {
$this->execute("behat_forms::set_field_value", [$comboboxname, $itemname]);
$this->execute("behat_general::wait_until_exists", [$itemname, "list_item"]);
}
return $dropdown;
}
/**
* Confirm if a value exists within the search combo box.
*
* Examples:
* - I confirm "User" exists in the "Search users" search combo box
* - I confirm "Group" exists in the "Search groups" search combo box
* - I confirm "Grade item" exists in the "Search grade items" search combo box
*
* @Given /^I confirm "(?P<itemname>(?:[^"]|\\")*)" exists in the "(?P<comboboxname>(?:[^"]|\\")*)" search combo box$/
* @param string $itemname The name of the combo box item we are searching for. This is only used if $fieldset is set
* to true.
* @param string $comboboxname The name (label) of the search combo box element. (e.g. "Search users", "Search groups").
*/
public function i_confirm_in_search_combobox_exists(string $itemname, string $comboboxname): void {
$this->execute("behat_general::assert_element_contains_text",
[$itemname, $this->get_combobox_dropdown_node($comboboxname, $itemname, false), "NodeElement"]);
}
/**
* Confirm if a value does not exist within the search combo box.
*
* Examples:
* - I confirm "User" does not exist in the "Search users" search combo box
* - I confirm "Group" does not exist in the "Search groups" search combo box
* - I confirm "Grade item" does not exist in the "Search grade items" search combo box
*
* @Given /^I confirm "(?P<itemname>(?:[^"]|\\")*)" does not exist in the "(?P<comboboxname>(?:[^"]|\\")*)" search combo box$/
* @param string $itemname The name of the combo box item we are searching for. This is only used if $fieldset is set
* to true.
* @param string $comboboxname The name (label) of the search combo box element. (e.g. "Search users", "Search groups").
*/
public function i_confirm_in_search_combobox_does_not_exist(string $itemname, string $comboboxname): void {
$this->execute("behat_general::assert_element_not_contains_text",
[$itemname, $this->get_combobox_dropdown_node($comboboxname, $itemname, false), "NodeElement"]);
}
/**
* Clicks on an option from the specified search widget.
*
* Examples:
* - I click on "Student" in the "Search users" search combo box
* - I click on "Group" in the "Search groups" search combo box
* - I click on "Grade item" in the "Search grade items" search combo box
*
* @Given /^I click on "(?P<itemname>(?:[^"]|\\")*)" in the "(?P<comboboxname>(?:[^"]|\\")*)" search combo box$/
* @param string $itemname The name of the combo box item we are searching for. This is only used if $fieldset is set
* to true.
* @param string $comboboxname The name (label) of the search combo box element. (e.g. "Search users", "Search groups").
*/
public function i_click_on_in_search_combobox(string $itemname, string $comboboxname): void {
$node = $this->get_combobox_dropdown_node($comboboxname, $itemname);
$this->execute('behat_general::i_click_on_in_the', [
$itemname, "list_item",
$node, "NodeElement",
]);
$this->execute("behat_general::i_wait_to_be_redirected");
}
}
+10
View File
@@ -0,0 +1,10 @@
define("mod_assign/repository",["exports","core/ajax"],(function(_exports,_ajax){var obj;
/**
* A repo for the search partial in the submissions page.
*
* @module mod_assign/repository
* @copyright 2024 Ilya Tregubov <ilyatregubov@proton.me>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.userFetch=void 0,_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};_exports.userFetch=(assignid,groupid)=>{const request={methodname:"mod_assign_list_participants",args:{assignid:assignid,groupid:groupid,filter:""}};return _ajax.default.call([request])[0]}}));
//# sourceMappingURL=repository.min.js.map
@@ -0,0 +1 @@
{"version":3,"file":"repository.min.js","sources":["../src/repository.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * A repo for the search partial in the submissions page.\n *\n * @module mod_assign/repository\n * @copyright 2024 Ilya Tregubov <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ajax from 'core/ajax';\n\n/**\n * Given a course ID, we want to fetch the learners within this assignment.\n *\n * @method userFetch\n * @param {int} assignid ID of the assignment.\n * @param {int} groupid ID of the selected group.\n * @return {object} jQuery promise\n */\nexport const userFetch = (assignid, groupid) => {\n const request = {\n methodname: 'mod_assign_list_participants',\n args: {\n assignid: assignid,\n groupid: groupid,\n filter: '',\n },\n };\n return ajax.call([request])[0];\n};\n"],"names":["assignid","groupid","request","methodname","args","filter","ajax","call"],"mappings":";;;;;;;8JAiCyB,CAACA,SAAUC,iBAC1BC,QAAU,CACZC,WAAY,+BACZC,KAAM,CACFJ,SAAUA,SACVC,QAASA,QACTI,OAAQ,YAGTC,cAAKC,KAAK,CAACL,UAAU"}
+11
View File
@@ -0,0 +1,11 @@
define("mod_assign/user",["exports","core_user/comboboxsearch/user","mod_assign/repository"],(function(_exports,_user,Repository){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_user=(obj=_user)&&obj.__esModule?obj:{default:obj},Repository=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Repository);const selectors_component=".user-search",selectors_groupid='[data-region="groupid"]',selectors_instance='[data-region="instance"]',component=document.querySelector(selectors_component),groupID=parseInt(component.querySelector(selectors_groupid).dataset.groupid,10),assignID=parseInt(component.querySelector(selectors_instance).dataset.instance,10);
/**
* Allow the user to search for users in the action bar.
*
* @module mod_assign/user
* @copyright 2024 Ilya Tregubov <ilyatregubov@proton.me>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class User extends _user.default{constructor(baseUrl){super(),this.baseUrl=baseUrl}static init(baseUrl){return new User(baseUrl)}selectAllResultsLink(){const url=new URL(this.baseUrl);return url.searchParams.set("search",this.getSearchTerm()),url.toString()}fetchDataset(){return Repository.userFetch(assignID,groupID).then((r=>r))}selectOneLink(userID){const url=new URL(this.baseUrl);return url.searchParams.set("search",this.getSearchTerm()),url.searchParams.set("userid",userID.toString()),url.toString()}}return _exports.default=User,_exports.default}));
//# sourceMappingURL=user.min.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"user.min.js","sources":["../src/user.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\nimport UserSearch from 'core_user/comboboxsearch/user';\nimport * as Repository from 'mod_assign/repository';\n\n// Define our standard lookups.\nconst selectors = {\n component: '.user-search',\n groupid: '[data-region=\"groupid\"]',\n instance: '[data-region=\"instance\"]',\n currentvalue: '[data-region=\"currentvalue\"]',\n};\nconst component = document.querySelector(selectors.component);\nconst groupID = parseInt(component.querySelector(selectors.groupid).dataset.groupid, 10);\nconst assignID = parseInt(component.querySelector(selectors.instance).dataset.instance, 10);\n\n/**\n * Allow the user to search for users in the action bar.\n *\n * @module mod_assign/user\n * @copyright 2024 Ilya Tregubov <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default class User extends UserSearch {\n\n /**\n * Construct the class.\n *\n * @param {string} baseUrl The base URL for the page.\n */\n constructor(baseUrl) {\n super();\n this.baseUrl = baseUrl;\n }\n\n /**\n * Allow the class to be invoked via PHP.\n *\n * @param {string} baseUrl The base URL for the page.\n * @returns {User}\n */\n static init(baseUrl) {\n return new User(baseUrl);\n }\n\n /**\n * Build up the view all link.\n *\n * @returns {string|*}\n */\n selectAllResultsLink() {\n const url = new URL(this.baseUrl);\n url.searchParams.set('search', this.getSearchTerm());\n\n return url.toString();\n }\n\n /**\n * Get the data we will be searching against in this component.\n *\n * @returns {Promise<*>}\n */\n fetchDataset() {\n return Repository.userFetch(assignID, groupID).then((r) => r);\n }\n\n /**\n * Build up the link that is dedicated to a particular result.\n *\n * @param {Number} userID The ID of the user selected.\n * @returns {string|*}\n */\n selectOneLink(userID) {\n const url = new URL(this.baseUrl);\n url.searchParams.set('search', this.getSearchTerm());\n url.searchParams.set('userid', userID.toString());\n\n return url.toString();\n }\n}\n"],"names":["selectors","component","document","querySelector","groupID","parseInt","dataset","groupid","assignID","instance","User","UserSearch","constructor","baseUrl","selectAllResultsLink","url","URL","this","searchParams","set","getSearchTerm","toString","fetchDataset","Repository","userFetch","then","r","selectOneLink","userID"],"mappings":"2sCAmBMA,oBACS,eADTA,kBAEO,0BAFPA,mBAGQ,2BAGRC,UAAYC,SAASC,cAAcH,qBACnCI,QAAUC,SAASJ,UAAUE,cAAcH,mBAAmBM,QAAQC,QAAS,IAC/EC,SAAWH,SAASJ,UAAUE,cAAcH,oBAAoBM,QAAQG,SAAU;;;;;;;;MASnEC,aAAaC,cAO9BC,YAAYC,sBAEHA,QAAUA,oBASPA,gBACD,IAAIH,KAAKG,SAQpBC,6BACUC,IAAM,IAAIC,IAAIC,KAAKJ,gBACzBE,IAAIG,aAAaC,IAAI,SAAUF,KAAKG,iBAE7BL,IAAIM,WAQfC,sBACWC,WAAWC,UAAUhB,SAAUJ,SAASqB,MAAMC,GAAMA,IAS/DC,cAAcC,cACJb,IAAM,IAAIC,IAAIC,KAAKJ,gBACzBE,IAAIG,aAAaC,IAAI,SAAUF,KAAKG,iBACpCL,IAAIG,aAAaC,IAAI,SAAUS,OAAOP,YAE/BN,IAAIM"}
+44
View File
@@ -0,0 +1,44 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* A repo for the search partial in the submissions page.
*
* @module mod_assign/repository
* @copyright 2024 Ilya Tregubov <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import ajax from 'core/ajax';
/**
* Given a course ID, we want to fetch the learners within this assignment.
*
* @method userFetch
* @param {int} assignid ID of the assignment.
* @param {int} groupid ID of the selected group.
* @return {object} jQuery promise
*/
export const userFetch = (assignid, groupid) => {
const request = {
methodname: 'mod_assign_list_participants',
args: {
assignid: assignid,
groupid: groupid,
filter: '',
},
};
return ajax.call([request])[0];
};
+93
View File
@@ -0,0 +1,93 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
import UserSearch from 'core_user/comboboxsearch/user';
import * as Repository from 'mod_assign/repository';
// Define our standard lookups.
const selectors = {
component: '.user-search',
groupid: '[data-region="groupid"]',
instance: '[data-region="instance"]',
currentvalue: '[data-region="currentvalue"]',
};
const component = document.querySelector(selectors.component);
const groupID = parseInt(component.querySelector(selectors.groupid).dataset.groupid, 10);
const assignID = parseInt(component.querySelector(selectors.instance).dataset.instance, 10);
/**
* Allow the user to search for users in the action bar.
*
* @module mod_assign/user
* @copyright 2024 Ilya Tregubov <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
export default class User extends UserSearch {
/**
* Construct the class.
*
* @param {string} baseUrl The base URL for the page.
*/
constructor(baseUrl) {
super();
this.baseUrl = baseUrl;
}
/**
* Allow the class to be invoked via PHP.
*
* @param {string} baseUrl The base URL for the page.
* @returns {User}
*/
static init(baseUrl) {
return new User(baseUrl);
}
/**
* Build up the view all link.
*
* @returns {string|*}
*/
selectAllResultsLink() {
const url = new URL(this.baseUrl);
url.searchParams.set('search', this.getSearchTerm());
return url.toString();
}
/**
* Get the data we will be searching against in this component.
*
* @returns {Promise<*>}
*/
fetchDataset() {
return Repository.userFetch(assignID, groupID).then((r) => r);
}
/**
* Build up the link that is dedicated to a particular result.
*
* @param {Number} userID The ID of the user selected.
* @returns {string|*}
*/
selectOneLink(userID) {
const url = new URL(this.baseUrl);
url.searchParams.set('search', this.getSearchTerm());
url.searchParams.set('userid', userID.toString());
return url.toString();
}
}
@@ -24,6 +24,8 @@
namespace mod_assign\output;
use assign;
use context_module;
use templatable;
use renderable;
use moodle_url;
@@ -71,14 +73,35 @@ class grading_actionmenu implements templatable, renderable {
$course = $PAGE->course;
$data = [];
$context = context_module::instance($this->cmid);
$assign = new assign($context, null, null);
$assignid = $assign->get_instance()->id;
if ($this->submissionpluginenabled && $this->submissioncount) {
$data['downloadall'] = (
new moodle_url('/mod/assign/view.php', ['id' => $this->cmid, 'action' => 'downloadall'])
)->out(false);
}
$userid = optional_param('userid', null, PARAM_INT);
// If the user ID is set, it indicates that a user has been selected. In this case, override the user search
// string with the full name of the selected user.
$usersearch = $userid ? fullname(\core_user::get_user($userid)) : optional_param('search', '', PARAM_NOTAGS);
$actionbarrenderer = $PAGE->get_renderer('core_course', 'actionbar');
$resetlink = new moodle_url('/mod/assign/view.php', ['id' => $this->cmid, 'action' => 'grading']);
$groupid = groups_get_course_group($course, true);
$userselector = new \core_course\output\actionbar\user_selector(
course: $course,
resetlink: $resetlink,
userid: $userid,
groupid: $groupid,
usersearch: $usersearch,
instanceid: $assignid
);
$data['userselector'] = $actionbarrenderer->render($userselector);
if ($course->groupmode) {
$actionbarrenderer = $PAGE->get_renderer('core_course', 'actionbar');
$data['groupselector'] = $actionbarrenderer->render(new \core_course\output\actionbar\group_selector($course));
}
+6
View File
@@ -124,6 +124,12 @@ class assign_grading_table extends table_sql implements renderable {
$this->rownum = $rowoffset - 1;
}
$userid = optional_param('userid', null, PARAM_INT);
$groupid = groups_get_course_group($assignment->get_course(), true);
// If the user ID is set, it indicates that a user has been selected. In this case, override the user search
// string with the full name of the selected user.
$usersearch = $userid ? fullname(\core_user::get_user($userid)) : optional_param('search', '', PARAM_NOTAGS);
$assignment->set_usersearch($userid, $groupid, $usersearch);
$users = array_keys( $assignment->list_participants($currentgroup, true));
if (count($users) == 0) {
// Insert a record that will never match to the sql is still valid.
+35
View File
@@ -208,6 +208,9 @@ class assign {
/** @var float grade value. */
public $grade;
/** @var array $usersearch The content that the current user is looking for. */
protected array $usersearch = [];
/**
* Constructor for the base assign class.
*
@@ -337,6 +340,21 @@ class assign {
$this->course = $course;
}
/**
* Set usersearch to limit results when getting list of participants.
*
* @param int|null $userid User id to search for.
* @param int|null $groupid Group id to limit resuts to specific group.
* @param string $usersearch Search string to limit results.
*/
public function set_usersearch(?int $userid, ?int $groupid, string $usersearch = ''): void {
$usersearcharray = [];
$usersearcharray['userid'] = $userid;
$usersearcharray['groupid'] = $groupid;
$usersearcharray['usersearch'] = $usersearch;
$this->usersearch = $usersearcharray;
}
/**
* Set error message.
*
@@ -2320,6 +2338,21 @@ class assign {
$params['markerid'] = $USER->id;
}
// A user wants to view a particular user rather than a set of users.
if ($this->usersearch) {
if (isset($this->usersearch['userid'])) {
$additionalfilters .= " AND u.id = :uid";
$params['uid'] = $this->usersearch['userid'];
} else if ($this->usersearch['usersearch'] !== '') { // A user wants to view a subset of learners that match the search criteria.
[
'where' => $keywordswhere,
'params' => $keywordsparams,
] = \core_user::get_users_search_sql($this->context, $this->usersearch['usersearch']);
$additionalfilters .= " AND $keywordswhere";
$params = array_merge($params, $keywordsparams);
}
}
$sql = "SELECT $fields
FROM {user} u
JOIN ($esql UNION $ssql) je ON je.id = u.id
@@ -4570,6 +4603,8 @@ class assign {
$currenturl = new moodle_url('/mod/assign/view.php', ['id' => $this->get_course_module()->id, 'action' => 'grading']);
$PAGE->activityheader->set_attrs(['hidecompletion' => true]);
$PAGE->requires->js_call_amd('mod_assign/user', 'init', [$currenturl->out(false)]);
// Conditionally add the group JS if we have groups enabled.
if ($this->get_course()->groupmode) {
$PAGE->requires->js_call_amd('core_course/actionbar/group', 'init', [$currenturl->out(false)]);
@@ -23,10 +23,12 @@
* none
Context variables required for this template:
* userselector - HTML that outputs the user selector
* groupselector - (optional) HTML that outputs the group selector
Example context (json):
{
"userselector": "<div class='user-search'></div>",
"groupselector": "<div class='group-selector'></div>",
"pagereset": "http://moodle.local/mod/assign/view.php?id=2&action=grading&group=0",
"downloadall": "https://moodle.org"
@@ -39,6 +41,12 @@
<h2>{{#str}}gradeitem:submissions, mod_assign{{/str}}</h2>
</div>
<div class="navitem-divider d-none d-sm-flex"></div>
{{#userselector}}
<div class="navitem">
{{{.}}}
</div>
<div class="navitem-divider d-none d-sm-flex"></div>
{{/userselector}}
{{#groupselector}}
<div class="navitem">
{{{.}}}
@@ -97,11 +97,11 @@ Feature: Group assignment submissions
| student1 | G1 |
And I am on the "Test assignment name" "assign activity" page
And I follow "View all submissions"
And I click on "Group 1" in the "group" search widget
And I click on "Group 1" in the "Search groups" search combo box
And I should see "Group 1" in the "Student 0" "table_row"
And I should see "Group 1" in the "Student 1" "table_row"
And I should not see "Student 2"
And I click on "All participants" in the "group" search widget
And I click on "All participants" in the "Search groups" search combo box
And I should see "Group 1" in the "Student 0" "table_row"
And I should see "Group 1" in the "Student 1" "table_row"
And I should see "Default group" in the "Student 2" "table_row"
@@ -0,0 +1,313 @@
@mod @mod_assign @javascript
Feature: Within the assignment submissions page, test that we can search for users
In order to filter specific users in the assignment submissions page
As a teacher
I need to be able to see and trigger the search filter
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode | groupmodeforce |
| Course 1 | C1 | 0 | 1 | 1 |
And the following "users" exist:
| username | firstname | lastname | email | idnumber | phone1 | phone2 | department | institution | city | country |
| teacher1 | Teacher | 1 | teacher1@example.com | t1 | 1234567892 | 1234567893 | ABC1 | ABCD | Perth | AU |
| student1 | Student | 1 | student1@example.com | s1 | 3213078612 | 8974325612 | ABC1 | ABCD | Hanoi | VN |
| student2 | Dummy | User | student2@example.com | s2 | 4365899871 | 7654789012 | ABC2 | ABCD | Tokyo | JP |
| student3 | User | Example | student3@example.com | s3 | 3243249087 | 0875421745 | ABC2 | ABCD | Olney | GB |
| student4 | User | Test | student4@example.com | s4 | 0987532523 | 2149871323 | ABC3 | ABCD | Tokyo | JP |
| student5 | Turtle | Manatee | student5@example.com | s5 | 1239087780 | 9873623589 | ABC3 | ABCD | Perth | AU |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
| student4 | C1 | student |
| student5 | C1 | student |
And the following "groups" exist:
| name | course | idnumber |
| Default group | C1 | dg |
| Advanced group | C1 | ag |
And the following "group members" exist:
| user | group |
| student3 | ag |
| student5 | dg |
And the following "activities" exist:
| activity | course | name |
| assign | C1 | Test assignment one |
And the following config values are set as admin:
| showuseridentity | idnumber,email,city,country,phone1,phone2,department,institution |
And I am on the "Test assignment one" Activity page logged in as teacher1
And I follow "View all submissions"
And I change window size to "large"
Scenario: A teacher can view and trigger the user search
# Check the placeholder text
Given I should see "Search users"
# Confirm the search is currently inactive and results are unfiltered.
And the following should exist in the "generaltable" table:
| -1- |
| Turtle Manatee |
| Student 1 |
| User Example |
| User Test |
| Dummy User |
And the following should not exist in the "generaltable" table:
| -1- |
| Teacher 1 |
When I set the field "Search users" to "Turtle"
And I wait until "View all results (1)" "option_role" exists
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
And I confirm "User Example" does not exist in the "Search users" search combo box
And I click on "Turtle Manatee" "list_item"
# Business case: This will trigger a page reload and can not dynamically update the table.
And I wait until the page is ready
Then the following should exist in the "generaltable" table:
| -1- |
| Turtle Manatee |
And the following should not exist in the "generaltable" table:
| -1- |
| Teacher 1 |
| Student 1 |
| User Example |
| User Test |
| Dummy User |
And I set the field "Search users" to "Turt"
And I wait until "View all results (1)" "option_role" exists
And I click on "Clear search input" "button" in the ".user-search" "css_element"
And "View all results (1)" "option_role" should not be visible
Scenario: A teacher can search to find specified users
# Case: Standard search.
Given I set the field "Search users" to "Dummy User"
And I wait until "View all results (1)" "option_role" exists
When I click on "Dummy User" "list_item"
Then the following should exist in the "generaltable" table:
| -1- |
| Dummy User |
And the following should not exist in the "generaltable" table:
| -1- |
| Teacher 1 |
| Student 1 |
| User Example |
| User Test |
| Turtle Manatee |
# Case: No users found.
When I set the field "Search users" to "Plagiarism"
And I should see "No results for \"Plagiarism\""
# Table remains unchanged as the user had no results to select from the dropdown.
And the following should exist in the "generaltable" table:
| -1- |
| Dummy User |
And the following should not exist in the "generaltable" table:
| -1- |
| Teacher 1 |
| Student 1 |
| User Example |
| User Test |
| Turtle Manatee |
# Case: Multiple users found and select only one result.
Then I set the field "Search users" to "User"
And I wait until "View all results (3)" "option_role" exists
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" does not exist in the "Search users" search combo box
# Check if the matched field names (by lines) includes some identifiable info to help differentiate similar users.
And I confirm "User (student2@example.com)" exists in the "Search users" search combo box
And I confirm "User (student3@example.com)" exists in the "Search users" search combo box
And I confirm "User (student4@example.com)" exists in the "Search users" search combo box
And I click on "Dummy User" "list_item"
And I wait until the page is ready
And the following should exist in the "generaltable" table:
| -1- |
| Dummy User |
And the following should not exist in the "generaltable" table:
| -1- |
| Teacher 1 |
| Student 1 |
| User Example |
| User Test |
| Turtle Manatee |
# Business case: When searching with multiple partial matches, show the matches in the dropdown + a "View all results for (Bob)"
# Business case cont. When pressing enter with multiple partial matches, behave like when you select the "View all results for (Bob)"
# Case: Multiple users found and select all partial matches.
And I set the field "Search users" to "User"
And I wait until "View all results (3)" "option_role" exists
# Dont need to check if all users are in the dropdown, we checked that earlier in this test.
And I click on "View all results (3)" "option_role"
And I wait until the page is ready
And the following should exist in the "generaltable" table:
| -1- |
| Dummy User |
| User Example |
| User Test |
And the following should not exist in the "generaltable" table:
| -1- |
| Teacher 1 |
| Student 1 |
| Turtle Manatee |
And I click on "Clear" "link" in the ".user-search" "css_element"
And I wait until the page is ready
And the following should exist in the "generaltable" table:
| -1- |
| Turtle Manatee |
| Student 1 |
| User Example |
| User Test |
| Dummy User |
Scenario: A teacher can quickly tell that a search is active on the current table
When I click on "Turtle" in the "Search users" search combo box
# The search input should contain the name of the user we have selected, so that it is clear that the result pertains to a specific user.
Then the field "Search users" matches value "Turtle Manatee"
# Test if we can then further retain the turtle result set and further filter from there.
And I set the field "Search users" to "Turtle plagiarism"
And "Turtle Manatee" "list_item" should not be visible
And I should see "No results for \"Turtle plagiarism\""
Scenario: A teacher can search for values besides the users' name
Given I set the field "Search users" to "student5@example.com"
And I wait until "View all results (1)" "option_role" exists
And "Turtle Manatee" "list_item" should exist
And I set the field "Search users" to "@example.com"
And I wait until "View all results (5)" "option_role" exists
# Note: All learners match this email & showing emails is current default.
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the country field.
When I set the field "Search users" to "JP"
And I wait until "Turtle Manatee" "list_item" does not exist
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
# Search on the city field.
And I set the field "Search users" to "Hanoi"
And I wait until "User Test" "list_item" does not exist
And I confirm "Student 1" exists in the "Search users" search combo box
# Search on the institution field.
And I set the field "Search users" to "ABCD"
And I wait until "Dummy User" "list_item" exists
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the department field.
And I set the field "Search users" to "ABC3"
And I wait until "User Example" "list_item" does not exist
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Turtle Manatee" exists in the "Search users" search combo box
# Search on the phone1 field.
And I set the field "Search users" to "4365899871"
And I wait until "User Test" "list_item" does not exist
And I confirm "Dummy User" exists in the "Search users" search combo box
# Search on the phone2 field.
And I set the field "Search users" to "2149871323"
And I wait until "Dummy User" "list_item" does not exist
And I confirm "User Test" exists in the "Search users" search combo box
# Search on the institution field then press enter to show the record set.
And I set the field "Search users" to "ABC"
And I wait until "Turtle Manatee" "list_item" exists
And I confirm "Dummy User" exists in the "Search users" search combo box
And I confirm "User Example" exists in the "Search users" search combo box
And I confirm "User Test" exists in the "Search users" search combo box
And I confirm "Student 1" exists in the "Search users" search combo box
And I press the down key
And I press the enter key
And I wait "1" seconds
And the following should exist in the "generaltable" table:
| -1- |
| Student 1 |
And the following should not exist in the "generaltable" table:
| -1- |
| User Example |
| User Test |
| Dummy User |
| Turtle Manatee |
| Teacher 1 |
Scenario: A teacher can set focus and search using the input are with a keyboard
Given I set the field "Search users" to "ABC"
And the focused element is "Search users" "field"
And I wait until "Turtle Manatee" "option_role" exists
# Basic tests for the page.
When I press the down key
And ".active" "css_element" should exist in the "Student 1" "option_role"
And I press the up key
And ".active" "css_element" should exist in the "View all results (5)" "option_role"
And I press the down key
And ".active" "css_element" should exist in the "Student 1" "option_role"
And I press the escape key
And the focused element is "Search users" "field"
Then I set the field "Search users" to "Goodmeme"
And I press the down key
And the focused element is "Search users" "field"
And I set the field "Search users" to "ABC"
And I wait until "Turtle Manatee" "option_role" exists
And I press the down key
And ".active" "css_element" should exist in the "Student 1" "option_role"
# Lets check the tabbing order.
And I set the field "Search users" to "ABC"
And I click on "Search users" "field"
And I wait until "Turtle Manatee" "option_role" exists
And I press the tab key
And the focused element is "Clear search input" "button"
And I press the tab key
And ".groupsearchwidget" "css_element" should exist
# Ensure we can interact with the input & clear search options with the keyboard.
# Space & Enter have the same handling for triggering the two functionalities.
And I set the field "Search users" to "User"
And I press the up key
And I press the enter key
And I wait to be redirected
And the following should exist in the "generaltable" table:
| -1- |
| Dummy User |
| User Example |
| User Test |
And the following should not exist in the "generaltable" table:
| -1- |
| Teacher 1 |
| Student 1 |
| Turtle Manatee |
Scenario: Once a teacher searches, it'll apply the currently set filters and inform the teacher as such
# Set up a basic filtering case.
Given I click on "Advanced group" in the "Search groups" search combo box
And the following should exist in the "generaltable" table:
| -1- |
| User Example |
And the following should not exist in the "generaltable" table:
| -1- |
| Teacher 1 |
| Student 1 |
| User Test |
| Dummy User |
| Turtle Manatee |
# Begin the search checking if we are adhering the filters.
When I set the field "Search users" to "Turtle"
Then I confirm "Turtle Manatee" does not exist in the "Search users" search combo box
Scenario: As a teacher I can dynamically find users whilst ignoring pagination
Given "11" "users" exist with the following data:
| username | students[count] |
| firstname | Student |
| lastname | s[count] |
| email | students[count]@example.com |
And "11" "course enrolments" exist with the following data:
| user | students[count] |
| course | C1 |
| role |student |
And I reload the page
And the field "perpage" matches value "10"
And the following should not exist in the "generaltable" table:
| -1- |
| Student s11 |
When I set the field "Search users" to "11"
# One of the users' phone numbers also matches.
And I wait until "View all results (1)" "option_role" exists
Then I confirm "Student s11" exists in the "Search users" search combo box
@@ -37,7 +37,7 @@ Feature: Change grading options in an H5P activity
And the field "Grading method" matches value "Highest grade"
And I click on "Save and return to course" "button"
When I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Percentage |
| Awesome H5P package | 100.00 | 100.00 % |
@@ -49,7 +49,7 @@ Feature: Change grading options in an H5P activity
| Grading method | First attempt |
And I click on "Save and return to course" "button"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Percentage |
| Awesome H5P package | 0.00 | 0.00 % |
@@ -61,7 +61,7 @@ Feature: Change grading options in an H5P activity
| Grading method | Last attempt |
And I click on "Save and return to course" "button"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Percentage |
| Awesome H5P package | 0.00 | 0.00 % |
@@ -73,7 +73,7 @@ Feature: Change grading options in an H5P activity
| Grading method | Average grade |
And I click on "Save and return to course" "button"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Percentage |
| Awesome H5P package | 33.33 | 33.33 % |
@@ -85,7 +85,7 @@ Feature: Change grading options in an H5P activity
| Grading method | Don't calculate a grade |
And I click on "Save and return to course" "button"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Percentage |
| Awesome H5P package | - | - |
@@ -97,7 +97,7 @@ Feature: Change grading options in an H5P activity
| Enable attempt tracking | No |
And I click on "Save and return to course" "button"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Percentage |
| Awesome H5P package | - | - |
@@ -110,7 +110,7 @@ Feature: Change grading options in an H5P activity
| Grading method | Average grade |
And I click on "Save and return to course" "button"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Range | Percentage |
| Awesome H5P package | 33.33 | 0100 | 33.33 % |
@@ -122,7 +122,7 @@ Feature: Change grading options in an H5P activity
| Maximum grade | 50 |
And I click on "Save and return to course" "button"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Range | Percentage |
| Awesome H5P package | 16.67 | 050 | 33.33 % |
@@ -135,7 +135,7 @@ Feature: Change grading options in an H5P activity
| Grading method | Average grade |
And I click on "Save and return to course" "button"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Range | Percentage |
| Awesome H5P package | 33.33 | 0100 | 33.33 % |
@@ -147,7 +147,7 @@ Feature: Change grading options in an H5P activity
| Maximum grade | 50 |
And I click on "Save and return to course" "button"
And I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Range | Percentage |
| Awesome H5P package | 33.33 | 050 | 66.67 % |
@@ -80,7 +80,7 @@ Feature: Do a H5P attempt
And "3" row "Score" column of "table" table should contain "0"
And "4" row "Score" column of "table" table should contain "1"
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
And I click on "Student 1" in the "user" search widget
And I click on "Student 1" in the "Search users" search combo box
Then the following should exist in the "user-grade" table:
| Grade item | Grade | Percentage |
| Awesome H5P package | 50.00 | 50.00 % |
@@ -40,6 +40,7 @@
<span class="d-none" data-region="courseid" data-courseid="{{courseid}}"></span>
<span class="d-none" data-region="groupid" data-groupid="{{group}}"></span>
<span class="d-none" data-region="instance" data-instance="{{instance}}"></span>
<span class="d-none" data-region="currentvalue" data-currentvalue="{{currentvalue}}"></span>
{{< core/search_input_auto }}
{{$label}}{{#str}}searchusers, core{{/str}}{{/label}}
{{$placeholder}}{{#str}}searchusers, core{{/str}}{{/placeholder}}