mirror of
https://github.com/moodle/moodle.git
synced 2025-05-13 11:51:22 +02:00
MDL-79061 core: Mechanism for logging mutation feedbacks
* Create a mechanism for logging mutation feedbacks. * The mutation feedbacks are displayed as a toast by default. * Apply this logging mechanism on the course homepage to provide feedback for the results of actions performed on course modules and course sections.
This commit is contained in:
parent
76ff7600e4
commit
771f183646
course/format/amd
lang/en
lib/amd
build/local/reactive
src/local/reactive
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -14,6 +14,7 @@
|
|||||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import ajax from 'core/ajax';
|
import ajax from 'core/ajax';
|
||||||
|
import {get_string as getString} from "core/str";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default mutation manager
|
* Default mutation manager
|
||||||
@ -65,6 +66,11 @@ export default class {
|
|||||||
* @param {number} targetCmId optional target cm id (for moving actions)
|
* @param {number} targetCmId optional target cm id (for moving actions)
|
||||||
*/
|
*/
|
||||||
async _sectionBasicAction(stateManager, action, sectionIds, targetSectionId, targetCmId) {
|
async _sectionBasicAction(stateManager, action, sectionIds, targetSectionId, targetCmId) {
|
||||||
|
const logEntry = this._getLoggerEntry(stateManager, action, sectionIds, {
|
||||||
|
targetSectionId,
|
||||||
|
targetCmId,
|
||||||
|
itemType: 'section',
|
||||||
|
});
|
||||||
const course = stateManager.get('course');
|
const course = stateManager.get('course');
|
||||||
this.sectionLock(stateManager, sectionIds, true);
|
this.sectionLock(stateManager, sectionIds, true);
|
||||||
const updates = await this._callEditWebservice(
|
const updates = await this._callEditWebservice(
|
||||||
@ -76,6 +82,7 @@ export default class {
|
|||||||
);
|
);
|
||||||
stateManager.processUpdates(updates);
|
stateManager.processUpdates(updates);
|
||||||
this.sectionLock(stateManager, sectionIds, false);
|
this.sectionLock(stateManager, sectionIds, false);
|
||||||
|
stateManager.addLoggerEntry(await logEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,6 +94,11 @@ export default class {
|
|||||||
* @param {number} targetCmId optional target cm id (for moving actions)
|
* @param {number} targetCmId optional target cm id (for moving actions)
|
||||||
*/
|
*/
|
||||||
async _cmBasicAction(stateManager, action, cmIds, targetSectionId, targetCmId) {
|
async _cmBasicAction(stateManager, action, cmIds, targetSectionId, targetCmId) {
|
||||||
|
const logEntry = this._getLoggerEntry(stateManager, action, cmIds, {
|
||||||
|
targetSectionId,
|
||||||
|
targetCmId,
|
||||||
|
itemType: 'cm',
|
||||||
|
});
|
||||||
const course = stateManager.get('course');
|
const course = stateManager.get('course');
|
||||||
this.cmLock(stateManager, cmIds, true);
|
this.cmLock(stateManager, cmIds, true);
|
||||||
const updates = await this._callEditWebservice(
|
const updates = await this._callEditWebservice(
|
||||||
@ -98,6 +110,51 @@ export default class {
|
|||||||
);
|
);
|
||||||
stateManager.processUpdates(updates);
|
stateManager.processUpdates(updates);
|
||||||
this.cmLock(stateManager, cmIds, false);
|
this.cmLock(stateManager, cmIds, false);
|
||||||
|
stateManager.addLoggerEntry(await logEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get log entry for the current action.
|
||||||
|
* @param {StateManager} stateManager the current state manager
|
||||||
|
* @param {string} action the action name
|
||||||
|
* @param {int[]|null} itemIds the element ids
|
||||||
|
* @param {Object|undefined} data extra params for the log entry
|
||||||
|
* @param {string|undefined} data.itemType the element type (will be taken from action if none)
|
||||||
|
* @param {int|null|undefined} data.targetSectionId the target section id
|
||||||
|
* @param {int|null|undefined} data.targetCmId the target cm id
|
||||||
|
* @param {String|null|undefined} data.component optional component (for format plugins)
|
||||||
|
* @return {Object} the log entry
|
||||||
|
*/
|
||||||
|
async _getLoggerEntry(stateManager, action, itemIds, data = {}) {
|
||||||
|
const feedbackParams = {
|
||||||
|
action,
|
||||||
|
itemType: data.itemType ?? action.split('_')[0],
|
||||||
|
};
|
||||||
|
let batch = '';
|
||||||
|
if (itemIds.length > 1) {
|
||||||
|
feedbackParams.count = itemIds.length;
|
||||||
|
batch = '_batch';
|
||||||
|
} else if (itemIds.length === 1) {
|
||||||
|
const itemInfo = stateManager.get(feedbackParams.itemType, itemIds[0]);
|
||||||
|
feedbackParams.name = itemInfo.title ?? itemInfo.name;
|
||||||
|
// Apply shortener for modules like label.
|
||||||
|
}
|
||||||
|
if (data.targetSectionId) {
|
||||||
|
feedbackParams.targetSectionName = stateManager.get('section', data.targetSectionId).title;
|
||||||
|
}
|
||||||
|
if (data.targetCmId) {
|
||||||
|
feedbackParams.targetCmName = stateManager.get('cm', data.targetCmId).name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = await getString(
|
||||||
|
`${action.toLowerCase()}_feedback${batch}`,
|
||||||
|
data.component ?? 'core_courseformat',
|
||||||
|
feedbackParams
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
feedbackMessage: message,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,6 +22,13 @@
|
|||||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
$string['cm_hide_feedback'] = '{$a->name} is now hidden.';
|
||||||
|
$string['cm_moveleft_feedback'] = '{$a->name} has been moved to the left.';
|
||||||
|
$string['cm_moveright_feedback'] = '{$a->name} has been moved to the right.';
|
||||||
|
$string['cm_show_feedback'] = '{$a->name} is now shown.';
|
||||||
|
$string['cm_stealth_feedback'] = '{$a->name} is now available but not shown on the course page.';
|
||||||
$string['courseindex'] = 'Course index';
|
$string['courseindex'] = 'Course index';
|
||||||
$string['preference:coursesectionspreferences'] = 'Section user preferences for course {$a}';
|
$string['preference:coursesectionspreferences'] = 'Section user preferences for course {$a}';
|
||||||
$string['privacy:metadata:preference:coursesectionspreferences'] = 'Section user preferences like collapsed and expanded.';
|
$string['privacy:metadata:preference:coursesectionspreferences'] = 'Section user preferences like collapsed and expanded.';
|
||||||
|
$string['section_hide_feedback'] = 'The course section {$a->name} has been hidden.';
|
||||||
|
$string['section_show_feedback'] = 'The course section {$a->name} has been shown.';
|
||||||
|
17
lib/amd/build/local/reactive/logger.min.js
vendored
Normal file
17
lib/amd/build/local/reactive/logger.min.js
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
define("core/local/reactive/logger",["exports","core/toast"],(function(_exports,_toast){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default=
|
||||||
|
/**
|
||||||
|
* Default reactive mutations logger class.
|
||||||
|
*
|
||||||
|
* This logger is used by default by the StateManager to log mutation feedbacks
|
||||||
|
* and actions. By default, feedbacks will be displayed as a toast. However, the
|
||||||
|
* reactive instance can provide alternative loggers to provide advanced logging
|
||||||
|
* capabilities.
|
||||||
|
*
|
||||||
|
* @module core/local/reactive/logger
|
||||||
|
* @class Logger
|
||||||
|
* @copyright 2023 Ferran Recio <ferran@moodle.com>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class{constructor(){this._debug=!1}add(entry){entry.feedbackMessage&&(0,_toast.add)(entry.feedbackMessage)}},_exports.default}));
|
||||||
|
|
||||||
|
//# sourceMappingURL=logger.min.js.map
|
1
lib/amd/build/local/reactive/logger.min.js.map
Normal file
1
lib/amd/build/local/reactive/logger.min.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"logger.min.js","sources":["../../../src/local/reactive/logger.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 * Default reactive mutations logger class.\n *\n * This logger is used by default by the StateManager to log mutation feedbacks\n * and actions. By default, feedbacks will be displayed as a toast. However, the\n * reactive instance can provide alternative loggers to provide advanced logging\n * capabilities.\n *\n * @module core/local/reactive/logger\n * @class Logger\n * @copyright 2023 Ferran Recio <ferran@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Logger entry structure.\n *\n * @typedef {object} LoggerEntry\n * @property {string} feedbackMessage Feedback message.\n */\n\nimport {add as addToast} from 'core/toast';\n\n/**\n * Default reactive mutations logger class.\n * @class Logger\n */\nexport default class Logger {\n /**\n * Constructor.\n */\n constructor() {\n this._debug = false;\n }\n\n /**\n * Add a log entry.\n * @param {LoggerEntry} entry Log entry.\n */\n add(entry) {\n if (entry.feedbackMessage) {\n addToast(entry.feedbackMessage);\n }\n }\n}\n"],"names":["constructor","_debug","add","entry","feedbackMessage"],"mappings":";;;;;;;;;;;;;;MA8CIA,mBACSC,QAAS,EAOlBC,IAAIC,OACIA,MAAMC,gCACGD,MAAMC"}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
60
lib/amd/src/local/reactive/logger.js
Normal file
60
lib/amd/src/local/reactive/logger.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default reactive mutations logger class.
|
||||||
|
*
|
||||||
|
* This logger is used by default by the StateManager to log mutation feedbacks
|
||||||
|
* and actions. By default, feedbacks will be displayed as a toast. However, the
|
||||||
|
* reactive instance can provide alternative loggers to provide advanced logging
|
||||||
|
* capabilities.
|
||||||
|
*
|
||||||
|
* @module core/local/reactive/logger
|
||||||
|
* @class Logger
|
||||||
|
* @copyright 2023 Ferran Recio <ferran@moodle.com>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger entry structure.
|
||||||
|
*
|
||||||
|
* @typedef {object} LoggerEntry
|
||||||
|
* @property {string} feedbackMessage Feedback message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {add as addToast} from 'core/toast';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default reactive mutations logger class.
|
||||||
|
* @class Logger
|
||||||
|
*/
|
||||||
|
export default class Logger {
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
this._debug = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a log entry.
|
||||||
|
* @param {LoggerEntry} entry Log entry.
|
||||||
|
*/
|
||||||
|
add(entry) {
|
||||||
|
if (entry.feedbackMessage) {
|
||||||
|
addToast(entry.feedbackMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,8 @@
|
|||||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import Logger from 'core/local/reactive/logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* State manager class.
|
* State manager class.
|
||||||
*
|
*
|
||||||
@ -120,6 +122,8 @@ export default class StateManager {
|
|||||||
};
|
};
|
||||||
this.target.addEventListener('state:loaded', initialStateDone);
|
this.target.addEventListener('state:loaded', initialStateDone);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.logger = new Logger();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -443,6 +447,24 @@ export default class StateManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the logger class instance.
|
||||||
|
*
|
||||||
|
* Reactive instances can provide alternative loggers to provide advanced logging.
|
||||||
|
* @param {Logger} logger
|
||||||
|
*/
|
||||||
|
setLogger(logger) {
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new log entry into the reactive logger.
|
||||||
|
* @param {LoggerEntry} entry
|
||||||
|
*/
|
||||||
|
addLoggerEntry(entry) {
|
||||||
|
this.logger.add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an element from the state or form an alternative state object.
|
* Get an element from the state or form an alternative state object.
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user