Merge branch 'MDL-52046-main' of https://github.com/davewoloszyn/moodle
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
issueNumber: MDL-52046
|
||||
notes:
|
||||
core_reportbuilder:
|
||||
- message: >-
|
||||
The return type of the `set_checkbox_toggleall` callback, defined by
|
||||
system reports, can now be null. Use if the checkbox should not be shown
|
||||
for the row.
|
||||
type: improved
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
define("core_cohort/actions",["exports","core/event_dispatcher","core/notification","core/pending","core/prefetch","core/str","core_cohort/repository","core_reportbuilder/local/events","core_reportbuilder/local/selectors","core/local/inplace_editable/events"],(function(_exports,_event_dispatcher,_notification,_pending,_prefetch,_str,_repository,reportEvents,reportSelectors,_events2){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 _interopRequireWildcard(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]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
/**
|
||||
* Cohorts actions.
|
||||
*
|
||||
* @module core_cohort/actions
|
||||
* @copyright 2024 David Woloszyn <david.woloszyn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.registerEventListeners=_exports.init=void 0,_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending),reportEvents=_interopRequireWildcard(reportEvents),reportSelectors=_interopRequireWildcard(reportSelectors);const SELECTORS_CHECKBOXES='[data-togglegroup="report-select-all"][data-toggle="slave"]:checked',SELECTORS_DELETEBUTTON='[data-action="cohort-delete-selected"]',SELECTORS_EDITNAME='[data-itemtype="cohortname"]';_exports.init=()=>{(0,_prefetch.prefetchStrings)("core_cohort",["delcohortsconfirm"]),(0,_prefetch.prefetchStrings)("core",["delete","deleteselected","selectitem"]),registerEventListeners()};const registerEventListeners=()=>{document.addEventListener(_events2.eventTypes.elementUpdated,(async event=>{if(event.target.closest(SELECTORS_EDITNAME)){const newName=await(0,_str.getString)("selectitem","core",event.target.dataset.value),cohortId=event.target.dataset.itemid,checkbox=document.querySelector('input[value="'.concat(cohortId,'"]')),label=document.querySelector('label[for="'.concat(checkbox.id,'"]'));newName&&label&&(label.innerHTML=newName)}})),document.addEventListener("click",(event=>{const cohortDeleteSelected=event.target.closest(SELECTORS_DELETEBUTTON);if(cohortDeleteSelected){event.preventDefault();const reportElement=document.querySelector(reportSelectors.regions.report),cohortDeleteChecked=reportElement.querySelectorAll(SELECTORS_CHECKBOXES);if(0===cohortDeleteChecked.length)return;_notification.default.saveCancelPromise((0,_str.getString)("deleteselected","core"),(0,_str.getString)("delcohortsconfirm","core_cohort"),(0,_str.getString)("delete","core"),{triggerElement:cohortDeleteSelected}).then((()=>{const pendingPromise=new _pending.default("core_cohort/cohorts:delete"),deleteCohortIds=[...cohortDeleteChecked].map((check=>check.value));return(0,_repository.deleteCohorts)(deleteCohortIds).then((()=>((0,_event_dispatcher.dispatchEvent)(reportEvents.tableReload,{preservePagination:!0},reportElement),pendingPromise.resolve()))).catch(_notification.default.exception)})).catch((()=>{}))}}))};_exports.registerEventListeners=registerEventListeners}));
|
||||
|
||||
//# sourceMappingURL=actions.min.js.map
|
||||
File diff suppressed because one or more lines are too long
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
define("core_cohort/repository",["exports","core/ajax"],(function(_exports,_ajax){var obj;
|
||||
/**
|
||||
* Module to handle cohort AJAX requests.
|
||||
*
|
||||
* @module core_cohort/repository
|
||||
* @copyright 2024 David Woloszyn <david.woloszyn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.deleteCohorts=_exports.deleteCohort=void 0,_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};_exports.deleteCohort=cohort=>deleteCohorts([cohort]);const deleteCohorts=cohorts=>{const request={methodname:"core_cohort_delete_cohorts",args:{cohortids:cohorts}};return _ajax.default.call([request])[0]};_exports.deleteCohorts=deleteCohorts}));
|
||||
|
||||
//# 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 * Module to handle cohort AJAX requests.\n *\n * @module core_cohort/repository\n * @copyright 2024 David Woloszyn <[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 * Delete single cohort.\n *\n * @param {Number} cohort Cohort ID\n * @return {Promise}\n */\nexport const deleteCohort = cohort => deleteCohorts([cohort]);\n\n/**\n * Delete multiple cohorts.\n *\n * @param {Number[]} cohorts Cohort IDs\n * @return {Promise}\n */\nexport const deleteCohorts = cohorts => {\n const request = {\n methodname: 'core_cohort_delete_cohorts',\n args: {cohortids: cohorts}\n };\n\n return Ajax.call([request])[0];\n};\n"],"names":["cohort","deleteCohorts","cohorts","request","methodname","args","cohortids","Ajax","call"],"mappings":";;;;;;;2LA+B4BA,QAAUC,cAAc,CAACD,eAQxCC,cAAgBC,gBACnBC,QAAU,CACZC,WAAY,6BACZC,KAAM,CAACC,UAAWJ,iBAGfK,cAAKC,KAAK,CAACL,UAAU"}
|
||||
@@ -0,0 +1,115 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Cohorts actions.
|
||||
*
|
||||
* @module core_cohort/actions
|
||||
* @copyright 2024 David Woloszyn <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import {dispatchEvent} from 'core/event_dispatcher';
|
||||
import Notification from 'core/notification';
|
||||
import Pending from 'core/pending';
|
||||
import {prefetchStrings} from 'core/prefetch';
|
||||
import {getString} from 'core/str';
|
||||
import {deleteCohorts} from 'core_cohort/repository';
|
||||
import * as reportEvents from 'core_reportbuilder/local/events';
|
||||
import * as reportSelectors from 'core_reportbuilder/local/selectors';
|
||||
import {eventTypes} from 'core/local/inplace_editable/events';
|
||||
|
||||
const SELECTORS = {
|
||||
CHECKBOXES: '[data-togglegroup="report-select-all"][data-toggle="slave"]:checked',
|
||||
DELETEBUTTON: '[data-action="cohort-delete-selected"]',
|
||||
EDITNAME: '[data-itemtype="cohortname"]',
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise module.
|
||||
*/
|
||||
export const init = () => {
|
||||
|
||||
prefetchStrings('core_cohort', [
|
||||
'delcohortsconfirm',
|
||||
]);
|
||||
|
||||
prefetchStrings('core', [
|
||||
'delete',
|
||||
'deleteselected',
|
||||
'selectitem',
|
||||
]);
|
||||
|
||||
registerEventListeners();
|
||||
};
|
||||
|
||||
/**
|
||||
* Register event listeners.
|
||||
*/
|
||||
export const registerEventListeners = () => {
|
||||
|
||||
// Edit cohort name inplace.
|
||||
document.addEventListener(eventTypes.elementUpdated, async(event) => {
|
||||
|
||||
const editCohortName = event.target.closest(SELECTORS.EDITNAME);
|
||||
|
||||
if (editCohortName) {
|
||||
const newName = await getString('selectitem', 'core', event.target.dataset.value);
|
||||
const cohortId = event.target.dataset.itemid;
|
||||
const checkbox = document.querySelector(`input[value="${cohortId}"]`);
|
||||
const label = document.querySelector(`label[for="${checkbox.id}"]`);
|
||||
|
||||
if (newName && label) {
|
||||
label.innerHTML = newName;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Delete multiple cohorts.
|
||||
document.addEventListener('click', event => {
|
||||
|
||||
const cohortDeleteSelected = event.target.closest(SELECTORS.DELETEBUTTON);
|
||||
|
||||
if (cohortDeleteSelected) {
|
||||
event.preventDefault();
|
||||
|
||||
const reportElement = document.querySelector(reportSelectors.regions.report);
|
||||
const cohortDeleteChecked = reportElement.querySelectorAll(SELECTORS.CHECKBOXES);
|
||||
if (cohortDeleteChecked.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Notification.saveCancelPromise(
|
||||
getString('deleteselected', 'core'),
|
||||
getString('delcohortsconfirm', 'core_cohort'),
|
||||
getString('delete', 'core'),
|
||||
{triggerElement: cohortDeleteSelected}
|
||||
).then(() => {
|
||||
const pendingPromise = new Pending('core_cohort/cohorts:delete');
|
||||
const deleteCohortIds = [...cohortDeleteChecked].map(check => check.value);
|
||||
|
||||
// eslint-disable-next-line promise/no-nesting
|
||||
return deleteCohorts(deleteCohortIds)
|
||||
.then(() => {
|
||||
dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement);
|
||||
return pendingPromise.resolve();
|
||||
})
|
||||
.catch(Notification.exception);
|
||||
}).catch(() => {
|
||||
return;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Module to handle cohort AJAX requests.
|
||||
*
|
||||
* @module core_cohort/repository
|
||||
* @copyright 2024 David Woloszyn <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import Ajax from 'core/ajax';
|
||||
|
||||
/**
|
||||
* Delete single cohort.
|
||||
*
|
||||
* @param {Number} cohort Cohort ID
|
||||
* @return {Promise}
|
||||
*/
|
||||
export const deleteCohort = cohort => deleteCohorts([cohort]);
|
||||
|
||||
/**
|
||||
* Delete multiple cohorts.
|
||||
*
|
||||
* @param {Number[]} cohorts Cohort IDs
|
||||
* @return {Promise}
|
||||
*/
|
||||
export const deleteCohorts = cohorts => {
|
||||
const request = {
|
||||
methodname: 'core_cohort_delete_cohorts',
|
||||
args: {cohortids: cohorts}
|
||||
};
|
||||
|
||||
return Ajax.call([request])[0];
|
||||
};
|
||||
@@ -59,7 +59,18 @@ class cohorts extends system_report {
|
||||
|
||||
// Any columns required by actions should be defined here to ensure they're always available.
|
||||
$this->add_base_fields("{$entitymainalias}.id, {$entitymainalias}.contextid, {$entitymainalias}.visible, " .
|
||||
"{$entitymainalias}.component");
|
||||
"{$entitymainalias}.component, {$entitymainalias}.name");
|
||||
|
||||
$this->set_checkbox_toggleall(static function(stdClass $cohort): ?array {
|
||||
if (!has_capability('moodle/cohort:manage', context::instance_by_id($cohort->contextid))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
$cohort->id,
|
||||
get_string('selectitem', 'moodle', $cohort->name),
|
||||
];
|
||||
});
|
||||
|
||||
// Check if report needs to show a specific category.
|
||||
$contextid = $this->get_parameter('contextid', 0, PARAM_INT);
|
||||
|
||||
@@ -115,5 +115,21 @@ if (!empty($searchquery)) {
|
||||
]);
|
||||
}
|
||||
|
||||
// Show the report.
|
||||
echo $report->output();
|
||||
|
||||
// Show the delete selected button if there are records.
|
||||
if ($DB->record_exists('cohort', [])) {
|
||||
|
||||
echo $OUTPUT->render(new single_button(
|
||||
new moodle_url('#'),
|
||||
get_string('deleteselected'),
|
||||
'post',
|
||||
single_button::BUTTON_PRIMARY,
|
||||
['data-action' => 'cohort-delete-selected']
|
||||
));
|
||||
|
||||
$PAGE->requires->js_call_amd('core_cohort/actions', 'init');
|
||||
}
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
@core @core_cohort
|
||||
Feature: Delete cohorts
|
||||
In order to delete multiple cohorts
|
||||
As an admin
|
||||
I need to select specific cohorts and perform that action
|
||||
|
||||
Background:
|
||||
Given the following "cohorts" exist:
|
||||
| name | idnumber | contextlevel | reference | description |
|
||||
| Cohort 1 | cohort1 | System | | About cohort 1 |
|
||||
| Cohort 2 | cohort2 | System | | About cohort 2 |
|
||||
| Cohort 3 | cohort3 | System | | About cohort 3 |
|
||||
|
||||
@javascript
|
||||
Scenario: I can delete multiple cohorts using the checkboxes
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Users > Accounts > Cohorts" in site administration
|
||||
And I should see "Cohort 1"
|
||||
And I should see "Cohort 2"
|
||||
And I should see "Cohort 3"
|
||||
And I click on "Select 'Cohort 1'" "checkbox"
|
||||
And I click on "Select 'Cohort 2'" "checkbox"
|
||||
When I click on "Delete selected" "button"
|
||||
Then I should see "Do you really want to delete the selected cohorts?"
|
||||
And I click on "Delete" "button" in the "Delete selected" "dialogue"
|
||||
And I should not see "Cohort 1"
|
||||
And I should not see "Cohort 2"
|
||||
And I should see "Cohort 3"
|
||||
@@ -47,6 +47,7 @@ $string['currentusers'] = 'Current users';
|
||||
$string['currentusersmatching'] = 'Current users matching';
|
||||
$string['defaultcontext'] = 'Default context';
|
||||
$string['delcohort'] = 'Delete cohort';
|
||||
$string['delcohortsconfirm'] = 'Do you really want to delete the selected cohorts?';
|
||||
$string['delconfirm'] = 'Do you really want to delete cohort \'{$a}\'?';
|
||||
$string['description'] = 'Description';
|
||||
$string['displayedrows'] = '{$a->displayed} rows displayed out of {$a->total}.';
|
||||
|
||||
+2
-1
@@ -373,7 +373,8 @@ $functions = array(
|
||||
'classpath' => 'cohort/externallib.php',
|
||||
'description' => 'Deletes all specified cohorts.',
|
||||
'type' => 'write',
|
||||
'capabilities' => 'moodle/cohort:manage'
|
||||
'capabilities' => 'moodle/cohort:manage',
|
||||
'ajax' => true,
|
||||
),
|
||||
'core_cohort_get_cohort_members' => array(
|
||||
'classname' => 'core_cohort_external',
|
||||
|
||||
@@ -144,7 +144,7 @@ abstract class system_report extends base {
|
||||
* Define toggle all checkbox for the report, required row data should be defined by calling {@see add_base_fields}
|
||||
*
|
||||
* @param callable $callback Callback to return value/label for each checkbox, implementing the following signature:
|
||||
* function(stdClass $row): array containing value/label pair
|
||||
* function(stdClass $row): ?array containing value/label pair, or null if the checkbox should not be shown for the row
|
||||
*/
|
||||
final protected function set_checkbox_toggleall(callable $callback): void {
|
||||
$this->checkboxcallback = $callback;
|
||||
@@ -167,7 +167,11 @@ abstract class system_report extends base {
|
||||
$value = '';
|
||||
$label = get_string('selectall');
|
||||
} else {
|
||||
[$value, $label] = ($this->checkboxcallback)($row);
|
||||
$checkboxdata = ($this->checkboxcallback)($row);
|
||||
if ($checkboxdata === null) {
|
||||
return null;
|
||||
}
|
||||
[$value, $label] = $checkboxdata;
|
||||
}
|
||||
|
||||
return new checkbox_toggleall('report-select-all', $ismaster, [
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2024062700.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2024070300.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.5dev (Build: 20240627)'; // Human-friendly version name
|
||||
|
||||
Reference in New Issue
Block a user