Merge branch 'MDL-72682' of git://github.com/paulholden/moodle

This commit is contained in:
Jun Pataleta 2021-10-07 14:33:38 +08:00
commit 34b2639c70
13 changed files with 70 additions and 8 deletions

View File

@ -19,6 +19,7 @@ Feature: View task logs report and use its filters
| Name value | <name> |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "Filters applied"
And I should see "Filters (1)" in the "#dropdownFiltersButton" "css_element"
And the following should exist in the "reportbuilder-table" table:
| Type | Name |
| Scheduled | <match> |
@ -61,9 +62,12 @@ Feature: View task logs report and use its filters
| Result value | Fail |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "Filters applied"
And I should see "Filters (1)" in the "#dropdownFiltersButton" "css_element"
And I should see "Nothing to display"
And I click on "Reset" "button" in the "[data-region='report-filters']" "css_element"
And I should see "Filters reset"
And I should not see "Filters (1)" in the "#dropdownFiltersButton" "css_element"
And I should see "Filters" in the "#dropdownFiltersButton" "css_element"
And "[data-region='report-filters']" "css_element" should be visible
And the following fields in the "Result" "core_reportbuilder > Filter" match these values:
| Result operator | Is any value |

View File

@ -60,6 +60,7 @@ $string['filterisnotequalto'] = 'Is not equal to';
$string['filterlessthan'] = 'Less than';
$string['filterrange'] = 'Range';
$string['filtersapplied'] = 'Filters applied';
$string['filtersappliedx'] = 'Filters ({$a})';
$string['filtersreset'] = 'Filters reset';
$string['filterstartswith'] = 'Starts with';
$string['privacy:metadata:preference:reportfilter'] = 'Stored report filter values';

View File

@ -1,2 +1,2 @@
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("core_reportbuilder/filters",["exports","core/event_dispatcher","core/fragment","core/notification","core/pending","core/str","core/templates","core/toast","core_form/dynamicform","core_reportbuilder/local/events","core_reportbuilder/local/selectors","core_reportbuilder/local/repository/filters"],function(a,b,c,d,e,f,g,h,i,j,k,l){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;d=o(d);e=o(e);g=o(g);i=o(i);j=n(j);k=n(k);function m(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;m=function(){return a};return a}function n(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=m();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function o(a){return a&&a.__esModule?a:{default:a}}var p=function(a,m){var n=document.querySelector(k.forSystemReport(a)),o=n.querySelector(k.regions.filtersForm),p=new i.default(o,"\\core_reportbuilder\\form\\filter");p.addEventListener(p.events.FORM_SUBMITTED,function(a){a.preventDefault();(0,b.dispatchEvent)(j.tableReload,{},n);(0,f.get_string)("filtersapplied","core_reportbuilder").then(h.add).catch(d.default.exception)});p.addEventListener(p.events.NOSUBMIT_BUTTON_PRESSED,function(i){i.preventDefault();var k=new e.default("core_reportbuilder/filters:reset");(0,l.reset)(a).then(function(){return(0,f.get_string)("filtersreset","core_reportbuilder")}).then(h.add).then(function(){return(0,c.loadFragment)("core_reportbuilder","filters_form",m,{reportid:a,parameters:n.dataset.parameter})}).then(function(a,c){g.default.replaceNodeContents(o,a,c);(0,b.dispatchEvent)(j.tableReload,{},n);return k.resolve()}).catch(d.default.exception)});document.querySelector("#region-main").style.overflowX="visible"};a.init=p});
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("core_reportbuilder/filters",["exports","core/event_dispatcher","core/fragment","core/notification","core/pending","core/str","core/templates","core/toast","core_form/dynamicform","core_reportbuilder/local/events","core_reportbuilder/local/selectors","core_reportbuilder/local/repository/filters"],function(a,b,c,d,e,f,g,h,i,j,k,l){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;d=o(d);e=o(e);g=o(g);i=o(i);j=n(j);k=n(k);function m(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;m=function(){return a};return a}function n(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=m();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function o(a){return a&&a.__esModule?a:{default:a}}function p(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function q(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){p(h,d,e,f,g,"next",a)}function g(a){p(h,d,e,f,g,"throw",a)}f(void 0)})}}var r=function(){var a=q(regeneratorRuntime.mark(function a(b,c){var d;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:d=b.querySelector(k.regions.filterButtonLabel);if(!(0<c)){a.next=7;break}a.next=4;return(0,f.get_string)("filtersappliedx","core_reportbuilder",c);case 4:d.textContent=a.sent;a.next=10;break;case 7:a.next=9;return(0,f.get_string)("filters","moodle");case 9:d.textContent=a.sent;case 10:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),s=function(a,m){var n=document.querySelector(k.forSystemReport(a)),o=n.querySelector(k.regions.filtersForm),p=new i.default(o,"\\core_reportbuilder\\form\\filter");p.addEventListener(p.events.FORM_SUBMITTED,function(a){a.preventDefault();(0,b.dispatchEvent)(j.tableReload,{},n);r(n,a.detail);(0,f.get_string)("filtersapplied","core_reportbuilder").then(h.add).catch(d.default.exception)});p.addEventListener(p.events.NOSUBMIT_BUTTON_PRESSED,function(i){i.preventDefault();var k=new e.default("core_reportbuilder/filters:reset");(0,l.reset)(a).then(function(){return(0,f.get_string)("filtersreset","core_reportbuilder")}).then(h.add).then(function(){return(0,c.loadFragment)("core_reportbuilder","filters_form",m,{reportid:a,parameters:n.dataset.parameter})}).then(function(a,c){g.default.replaceNodeContents(o,a,c);(0,b.dispatchEvent)(j.tableReload,{},n);r(n,0);return k.resolve()}).catch(d.default.exception)});document.querySelector("#region-main").style.overflowX="visible"};a.init=s});
//# sourceMappingURL=filters.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
define ("core_reportbuilder/local/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;var b={regions:{systemReport:"[data-region=\"core_reportbuilder/system-report\"]",filtersForm:"[data-region=\"filters-form\"]"},actions:{reportActionPopup:"[data-action=\"report-action-popup\"]"}};b.forSystemReport=function(a){return"".concat(b.regions.systemReport,"[data-reportid=\"").concat(a,"\"]")};a.default=b;return a.default});
define ("core_reportbuilder/local/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;var b={regions:{systemReport:"[data-region=\"core_reportbuilder/system-report\"]",filterButtonLabel:"[data-region=\"filter-button-label\"]",filtersForm:"[data-region=\"filters-form\"]"},actions:{reportActionPopup:"[data-action=\"report-action-popup\"]"}};b.forSystemReport=function(a){return"".concat(b.regions.systemReport,"[data-reportid=\"").concat(a,"\"]")};a.default=b;return a.default});
//# sourceMappingURL=selectors.min.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["../../src/local/selectors.js"],"names":["SELECTORS","regions","systemReport","filtersForm","actions","reportActionPopup","forSystemReport","reportId"],"mappings":"oJA8BA,GAAMA,CAAAA,CAAS,CAAG,CACdC,OAAO,CAAE,CACLC,YAAY,CAAE,oDADT,CAELC,WAAW,CAAE,gCAFR,CADK,CAKdC,OAAO,CAAE,CACLC,iBAAiB,CAAE,uCADd,CALK,CAAlB,CAiBAL,CAAS,CAACM,eAAV,CAA4B,SAAAC,CAAQ,kBAAOP,CAAS,CAACC,OAAV,CAAkBC,YAAzB,6BAAwDK,CAAxD,QAApC,C,UAEeP,C","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 * Report builder selectors\n *\n * @module core_reportbuilder/local/selectors\n * @copyright 2021 Paul Holden <paulh@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Selectors for the Report builder subsystem\n *\n * @property {Object} regions\n * @property {String} regions.systemReport System report page region\n * @property {String} regions.filtersForm Filters form page region\n */\nconst SELECTORS = {\n regions: {\n systemReport: '[data-region=\"core_reportbuilder/system-report\"]',\n filtersForm: '[data-region=\"filters-form\"]',\n },\n actions: {\n reportActionPopup: '[data-action=\"report-action-popup\"]',\n }\n};\n\n/**\n * Selector for given report\n *\n * @method forSystemReport\n * @param {Number} reportId\n * @return {String}\n */\nSELECTORS.forSystemReport = reportId => `${SELECTORS.regions.systemReport}[data-reportid=\"${reportId}\"]`;\n\nexport default SELECTORS;\n"],"file":"selectors.min.js"}
{"version":3,"sources":["../../src/local/selectors.js"],"names":["SELECTORS","regions","systemReport","filterButtonLabel","filtersForm","actions","reportActionPopup","forSystemReport","reportId"],"mappings":"oJA+BA,GAAMA,CAAAA,CAAS,CAAG,CACdC,OAAO,CAAE,CACLC,YAAY,CAAE,oDADT,CAELC,iBAAiB,CAAE,uCAFd,CAGLC,WAAW,CAAE,gCAHR,CADK,CAMdC,OAAO,CAAE,CACLC,iBAAiB,CAAE,uCADd,CANK,CAAlB,CAkBAN,CAAS,CAACO,eAAV,CAA4B,SAAAC,CAAQ,kBAAOR,CAAS,CAACC,OAAV,CAAkBC,YAAzB,6BAAwDM,CAAxD,QAApC,C,UAEeR,C","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 * Report builder selectors\n *\n * @module core_reportbuilder/local/selectors\n * @copyright 2021 Paul Holden <paulh@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Selectors for the Report builder subsystem\n *\n * @property {Object} regions\n * @property {String} regions.systemReport System report page region\n * @property {String} regions.filterButtonLabel Filters form toggle region\n * @property {String} regions.filtersForm Filters form page region\n */\nconst SELECTORS = {\n regions: {\n systemReport: '[data-region=\"core_reportbuilder/system-report\"]',\n filterButtonLabel: '[data-region=\"filter-button-label\"]',\n filtersForm: '[data-region=\"filters-form\"]',\n },\n actions: {\n reportActionPopup: '[data-action=\"report-action-popup\"]',\n }\n};\n\n/**\n * Selector for given report\n *\n * @method forSystemReport\n * @param {Number} reportId\n * @return {String}\n */\nSELECTORS.forSystemReport = reportId => `${SELECTORS.regions.systemReport}[data-reportid=\"${reportId}\"]`;\n\nexport default SELECTORS;\n"],"file":"selectors.min.js"}

View File

@ -33,6 +33,22 @@ import * as reportEvents from 'core_reportbuilder/local/events';
import * as reportSelectors from 'core_reportbuilder/local/selectors';
import {reset as resetFilters} from 'core_reportbuilder/local/repository/filters';
/**
* Update filter button text to indicate applied filter count
*
* @param {Element} reportElement
* @param {Number} filterCount
*/
const setFilterButtonCount = async(reportElement, filterCount) => {
const filterButtonLabel = reportElement.querySelector(reportSelectors.regions.filterButtonLabel);
if (filterCount > 0) {
filterButtonLabel.textContent = await getString('filtersappliedx', 'core_reportbuilder', filterCount);
} else {
filterButtonLabel.textContent = await getString('filters', 'moodle');
}
};
/**
* Initialise module for given report
*
@ -51,6 +67,7 @@ export const init = (reportId, contextId) => {
// After the form has been submitted, we should trigger report table reload.
dispatchEvent(reportEvents.tableReload, {}, reportElement);
setFilterButtonCount(reportElement, event.detail);
getString('filtersapplied', 'core_reportbuilder')
.then(addToast)
@ -72,7 +89,9 @@ export const init = (reportId, contextId) => {
}))
.then((html, js) => {
Templates.replaceNodeContents(filterFormContainer, html, js);
dispatchEvent(reportEvents.tableReload, {}, reportElement);
setFilterButtonCount(reportElement, 0);
return pendingPromise.resolve();
})

View File

@ -26,11 +26,13 @@
*
* @property {Object} regions
* @property {String} regions.systemReport System report page region
* @property {String} regions.filterButtonLabel Filters form toggle region
* @property {String} regions.filtersForm Filters form page region
*/
const SELECTORS = {
regions: {
systemReport: '[data-region="core_reportbuilder/system-report"]',
filterButtonLabel: '[data-region="filter-button-label"]',
filtersForm: '[data-region="filters-form"]',
},
actions: {

View File

@ -67,6 +67,7 @@ class system_report_exporter extends persistent_exporter {
'table' => ['type' => PARAM_RAW],
'parameters' => ['type' => PARAM_RAW],
'filterspresent' => ['type' => PARAM_BOOL],
'filtersapplied' => ['type' => PARAM_INT],
'filtersform' => [
'type' => PARAM_RAW,
'optional' => true,
@ -109,6 +110,7 @@ class system_report_exporter extends persistent_exporter {
'table' => $output->render($table),
'parameters' => $this->related['parameters'],
'filterspresent' => $filterspresent,
'filtersapplied' => $source->get_applied_filter_count(),
'filtersform' => $filterspresent ? $filtersform->render() : '',
];
}

View File

@ -70,15 +70,16 @@ class filter extends dynamic_form {
/**
* Process the form submission
*
* @return bool
* @return int Number of applied filter instances
*/
public function process_dynamic_submission() {
$values = $this->get_data();
// Remove some unneeded fields.
// Remove some unneeded fields, apply filters.
unset($values->reportid, $values->parameters);
$this->get_system_report()->set_filter_values((array) $values);
return $this->get_system_report()->set_filter_values((array) $values);
return $this->get_system_report()->get_applied_filter_count();
}
/**

View File

@ -85,4 +85,18 @@ abstract class base {
* @return array [$sql, [...$params]]
*/
abstract public function get_sql_filter(array $values): array;
/**
* Given an array of current filter values for the report, determine whether the filter would apply to the report (i.e. user
* has configured it from it's initial "Any value" state). A filter would typically be considered applied if it returns SQL
* filter clauses, but child classes may override this method if they use different logic
*
* @param array $values
* @return bool
*/
public function applies_to_values(array $values): bool {
[$filtersql] = $this->get_sql_filter($values);
return $filtersql !== '';
}
}

View File

@ -442,6 +442,21 @@ abstract class base {
return user_filter_manager::get($this->report->get('id'));
}
/**
* Return the number of filter instances that are being applied based on the report's filter values (i.e. user has
* configured them from their initial "Any value" state)
*
* @return int
*/
final public function get_applied_filter_count(): int {
$values = $this->get_filter_values();
$applied = array_filter($this->get_filter_instances(), static function(filter_base $filter) use ($values): bool {
return $filter->applies_to_values($values);
});
return count($applied);
}
/**
* Set if the report can be downloaded.
*

View File

@ -23,6 +23,7 @@
{
"id": 3,
"contextid": 1,
"filtersapplied": 3,
"filtersform": "form"
}
}}
@ -31,7 +32,10 @@
<!-- Filters button -->
<button class="btn btn-sm btn-secondary" type="button" id="dropdownFiltersButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" title="{{#str}} filters, moodle {{/str}}">
{{#pix}} i/filter, core {{/pix}}
{{#str}} filters, moodle {{/str}}
<span data-region="filter-button-label">
{{#filtersapplied}} {{#str}} filtersappliedx, core_reportbuilder, {{filtersapplied}} {{/str}} {{/filtersapplied}}
{{^filtersapplied}} {{#str}} filters, moodle {{/str}} {{/filtersapplied}}
</span>
</button>
<!-- Filters content -->
<div class="filters-dropdown dropdown-menu dropdown-menu-right" aria-labelledby="dropdownFiltersButton">