From f4bf4dca363a98cd6ffcc09eda4870d6cce6903e Mon Sep 17 00:00:00 2001 From: Paul Holden Date: Thu, 18 Nov 2021 13:06:40 +0000 Subject: [PATCH] MDL-73112 reportbuilder: improve handling of concatenated columns. This change overcomes limitations in certain DB engines (such as MySQL[1]) which can lead to truncation of data when applying group concatenation to columns. Ensure we account for that by validating that we are able to extract the expected number of fields from each concatenated value. [1] https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_group_concat_max_len --- reportbuilder/amd/build/report.min.js | 2 +- reportbuilder/amd/build/report.min.js.map | 2 +- reportbuilder/amd/src/report.js | 4 +++- .../classes/local/aggregation/groupconcat.php | 12 ++++++++++-- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/reportbuilder/amd/build/report.min.js b/reportbuilder/amd/build/report.min.js index 39a67765906..83f3e5c1f15 100644 --- a/reportbuilder/amd/build/report.min.js +++ b/reportbuilder/amd/build/report.min.js @@ -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/report",["exports","core_reportbuilder/local/events","core_reportbuilder/local/selectors","core_table/dynamic","core_table/local/dynamic/selectors"],function(a,b,c,d,e){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=g(b);c=g(c);e=g(e);function f(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;f=function(){return a};return a}function g(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=f();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 g=d?Object.getOwnPropertyDescriptor(a,e):null;if(g&&(g.get||g.set)){Object.defineProperty(c,e,g)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function h(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 i(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var i=a.apply(b,c);function f(a){h(i,d,e,f,g,"next",a)}function g(a){h(i,d,e,f,g,"throw",a)}f(void 0)})}}var j={COLLAPSED:"collapsed",EXPANDED:"show",ICONUP:"fa-angle-up",ICONDOWN:"fa-angle-down"},k=!1,l=function(){if(k){return}document.addEventListener(b.tableReload,function(){var a=i(regeneratorRuntime.mark(function a(b){var f,g,h,i;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:g=b.target.closest(c.regions.report);if(!(null===g)){a.next=3;break}return a.abrupt("return");case 3:h=g.querySelector(e.main.region);i=(null===(f=b.detail)||void 0===f?void 0:f.preservePagination)?null:1;a.next=7;return(0,d.setPageNumber)(h,i,!1).then(d.refreshTableContent);case 7:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}());document.addEventListener("click",function(a){var b=a.target.closest(c.actions.reportActionPopup);if(null===b){return}a.preventDefault();var d=JSON.parse(b.dataset.popupAction);window.openpopup(a,d.jsfunctionargs)});document.addEventListener("click",function(a){var b=a.target.closest(c.actions.toggleCardView);if(b){var d=b.closest("tr"),e=b.querySelector("i");a.preventDefault();if(b.classList.contains(j.COLLAPSED)){d.classList.add(j.EXPANDED);e.classList.replace(j.ICONDOWN,j.ICONUP);b.classList.remove(j.COLLAPSED);b.setAttribute("aria-expanded","true")}else{d.classList.remove(j.EXPANDED);e.classList.replace(j.ICONUP,j.ICONDOWN);b.classList.add(j.COLLAPSED);b.removeAttribute("aria-expanded")}}});k=!0};a.init=l}); +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/report",["exports","core/notification","core_reportbuilder/local/events","core_reportbuilder/local/selectors","core_table/dynamic","core_table/local/dynamic/selectors"],function(a,b,c,d,e,f){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);c=h(c);d=h(d);f=h(f);function g(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;g=function(){return a};return a}function h(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=g();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 i(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 j(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){i(h,d,e,f,g,"next",a)}function g(a){i(h,d,e,f,g,"throw",a)}f(void 0)})}}var k={COLLAPSED:"collapsed",EXPANDED:"show",ICONUP:"fa-angle-up",ICONDOWN:"fa-angle-down"},l=!1,m=function(){if(l){return}document.addEventListener(c.tableReload,function(){var a=j(regeneratorRuntime.mark(function a(c){var g,h,i,j;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:h=c.target.closest(d.regions.report);if(!(null===h)){a.next=3;break}return a.abrupt("return");case 3:i=h.querySelector(f.main.region);j=(null===(g=c.detail)||void 0===g?void 0:g.preservePagination)?null:1;a.next=7;return(0,e.setPageNumber)(i,j,!1).then(e.refreshTableContent).catch(b.default.exception);case 7:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}());document.addEventListener("click",function(a){var b=a.target.closest(d.actions.reportActionPopup);if(null===b){return}a.preventDefault();var c=JSON.parse(b.dataset.popupAction);window.openpopup(a,c.jsfunctionargs)});document.addEventListener("click",function(a){var b=a.target.closest(d.actions.toggleCardView);if(b){var c=b.closest("tr"),e=b.querySelector("i");a.preventDefault();if(b.classList.contains(k.COLLAPSED)){c.classList.add(k.EXPANDED);e.classList.replace(k.ICONDOWN,k.ICONUP);b.classList.remove(k.COLLAPSED);b.setAttribute("aria-expanded","true")}else{c.classList.remove(k.EXPANDED);e.classList.replace(k.ICONUP,k.ICONDOWN);b.classList.add(k.COLLAPSED);b.removeAttribute("aria-expanded")}}});l=!0};a.init=m}); //# sourceMappingURL=report.min.js.map diff --git a/reportbuilder/amd/build/report.min.js.map b/reportbuilder/amd/build/report.min.js.map index f271139f87d..0b7d4d9434e 100644 --- a/reportbuilder/amd/build/report.min.js.map +++ b/reportbuilder/amd/build/report.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/report.js"],"names":["CLASSES","COLLAPSED","EXPANDED","ICONUP","ICONDOWN","initialized","init","document","addEventListener","reportEvents","tableReload","event","reportElement","target","closest","reportSelectors","regions","report","tableRoot","querySelector","tableSelectors","main","region","pageNumber","detail","preservePagination","then","refreshTableContent","reportActionPopup","actions","preventDefault","popupAction","JSON","parse","dataset","window","openpopup","jsfunctionargs","toggleCard","toggleCardView","tableCard","toggleIcon","classList","contains","add","replace","remove","setAttribute","removeAttribute"],"mappings":"ojBAuBA,OACA,OAEA,O,w2BAEMA,CAAAA,CAAO,CAAG,CACZC,SAAS,CAAE,WADC,CAEZC,QAAQ,CAAE,MAFE,CAGZC,MAAM,CAAE,aAHI,CAIZC,QAAQ,CAAE,eAJE,C,CAOZC,CAAW,G,CAOFC,CAAI,CAAG,UAAM,CAEtB,GAAID,CAAJ,CAAiB,CAEb,MACH,CAGDE,QAAQ,CAACC,gBAAT,CAA0BC,CAAY,CAACC,WAAvC,4CAAoD,WAAMC,CAAN,+FAC1CC,CAD0C,CAC1BD,CAAK,CAACE,MAAN,CAAaC,OAAb,CAAqBC,CAAe,CAACC,OAAhB,CAAwBC,MAA7C,CAD0B,MAE1B,IAAlB,GAAAL,CAF4C,mDAM1CM,CAN0C,CAM9BN,CAAa,CAACO,aAAd,CAA4BC,CAAc,CAACC,IAAf,CAAoBC,MAAhD,CAN8B,CAO1CC,CAP0C,CAO7B,WAAAZ,CAAK,CAACa,MAAN,uBAAcC,kBAAd,EAAmC,IAAnC,CAA0C,CAPb,gBAS1C,oBAAcP,CAAd,CAAyBK,CAAzB,KACDG,IADC,CACIC,qBADJ,CAT0C,yCAApD,yDAcApB,QAAQ,CAACC,gBAAT,CAA0B,OAA1B,CAAmC,SAAAG,CAAK,CAAI,CACxC,GAAMiB,CAAAA,CAAiB,CAAGjB,CAAK,CAACE,MAAN,CAAaC,OAAb,CAAqBC,CAAe,CAACc,OAAhB,CAAwBD,iBAA7C,CAA1B,CACA,GAA0B,IAAtB,GAAAA,CAAJ,CAAgC,CAC5B,MACH,CACDjB,CAAK,CAACmB,cAAN,GACA,GAAMC,CAAAA,CAAW,CAAGC,IAAI,CAACC,KAAL,CAAWL,CAAiB,CAACM,OAAlB,CAA0BH,WAArC,CAApB,CACAI,MAAM,CAACC,SAAP,CAAiBzB,CAAjB,CAAwBoB,CAAW,CAACM,cAApC,CACH,CARD,EAWA9B,QAAQ,CAACC,gBAAT,CAA0B,OAA1B,CAAmC,SAACG,CAAD,CAAW,CAC1C,GAAM2B,CAAAA,CAAU,CAAG3B,CAAK,CAACE,MAAN,CAAaC,OAAb,CAAqBC,CAAe,CAACc,OAAhB,CAAwBU,cAA7C,CAAnB,CACA,GAAID,CAAJ,CAAgB,IACNE,CAAAA,CAAS,CAAGF,CAAU,CAACxB,OAAX,CAAmB,IAAnB,CADN,CAEN2B,CAAU,CAAGH,CAAU,CAACnB,aAAX,CAAyB,GAAzB,CAFP,CAGZR,CAAK,CAACmB,cAAN,GACA,GAAIQ,CAAU,CAACI,SAAX,CAAqBC,QAArB,CAA8B3C,CAAO,CAACC,SAAtC,CAAJ,CAAsD,CAClDuC,CAAS,CAACE,SAAV,CAAoBE,GAApB,CAAwB5C,CAAO,CAACE,QAAhC,EACAuC,CAAU,CAACC,SAAX,CAAqBG,OAArB,CAA6B7C,CAAO,CAACI,QAArC,CAA+CJ,CAAO,CAACG,MAAvD,EACAmC,CAAU,CAACI,SAAX,CAAqBI,MAArB,CAA4B9C,CAAO,CAACC,SAApC,EACAqC,CAAU,CAACS,YAAX,CAAwB,eAAxB,CAAyC,MAAzC,CACH,CALD,IAKO,CACHP,CAAS,CAACE,SAAV,CAAoBI,MAApB,CAA2B9C,CAAO,CAACE,QAAnC,EACAuC,CAAU,CAACC,SAAX,CAAqBG,OAArB,CAA6B7C,CAAO,CAACG,MAArC,CAA6CH,CAAO,CAACI,QAArD,EACAkC,CAAU,CAACI,SAAX,CAAqBE,GAArB,CAAyB5C,CAAO,CAACC,SAAjC,EACAqC,CAAU,CAACU,eAAX,CAA2B,eAA3B,CACH,CACJ,CACJ,CAlBD,EAoBA3C,CAAW,GACd,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 .\n\n/**\n * Report builder report management\n *\n * @module core_reportbuilder/report\n * @copyright 2021 Paul Holden \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as reportEvents from 'core_reportbuilder/local/events';\nimport * as reportSelectors from 'core_reportbuilder/local/selectors';\nimport {setPageNumber, refreshTableContent} from 'core_table/dynamic';\nimport * as tableSelectors from 'core_table/local/dynamic/selectors';\n\nconst CLASSES = {\n COLLAPSED: 'collapsed',\n EXPANDED: 'show',\n ICONUP: 'fa-angle-up',\n ICONDOWN: 'fa-angle-down'\n};\n\nlet initialized = false;\n\n/**\n * Initialise module for given report\n *\n * @method\n */\nexport const init = () => {\n\n if (initialized) {\n // We already added the event listeners (can be called multiple times by mustache template).\n return;\n }\n\n // Listen for the table reload event.\n document.addEventListener(reportEvents.tableReload, async(event) => {\n const reportElement = event.target.closest(reportSelectors.regions.report);\n if (reportElement === null) {\n return;\n }\n\n const tableRoot = reportElement.querySelector(tableSelectors.main.region);\n const pageNumber = event.detail?.preservePagination ? null : 1;\n\n await setPageNumber(tableRoot, pageNumber, false)\n .then(refreshTableContent);\n });\n\n // Listen for trigger popup events.\n document.addEventListener('click', event => {\n const reportActionPopup = event.target.closest(reportSelectors.actions.reportActionPopup);\n if (reportActionPopup === null) {\n return;\n }\n event.preventDefault();\n const popupAction = JSON.parse(reportActionPopup.dataset.popupAction);\n window.openpopup(event, popupAction.jsfunctionargs);\n });\n\n // Listen for card view toggle events.\n document.addEventListener('click', (event) => {\n const toggleCard = event.target.closest(reportSelectors.actions.toggleCardView);\n if (toggleCard) {\n const tableCard = toggleCard.closest('tr');\n const toggleIcon = toggleCard.querySelector('i');\n event.preventDefault();\n if (toggleCard.classList.contains(CLASSES.COLLAPSED)) {\n tableCard.classList.add(CLASSES.EXPANDED);\n toggleIcon.classList.replace(CLASSES.ICONDOWN, CLASSES.ICONUP);\n toggleCard.classList.remove(CLASSES.COLLAPSED);\n toggleCard.setAttribute('aria-expanded', \"true\");\n } else {\n tableCard.classList.remove(CLASSES.EXPANDED);\n toggleIcon.classList.replace(CLASSES.ICONUP, CLASSES.ICONDOWN);\n toggleCard.classList.add(CLASSES.COLLAPSED);\n toggleCard.removeAttribute('aria-expanded');\n }\n }\n });\n\n initialized = true;\n};\n"],"file":"report.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/report.js"],"names":["CLASSES","COLLAPSED","EXPANDED","ICONUP","ICONDOWN","initialized","init","document","addEventListener","reportEvents","tableReload","event","reportElement","target","closest","reportSelectors","regions","report","tableRoot","querySelector","tableSelectors","main","region","pageNumber","detail","preservePagination","then","refreshTableContent","catch","Notification","exception","reportActionPopup","actions","preventDefault","popupAction","JSON","parse","dataset","window","openpopup","jsfunctionargs","toggleCard","toggleCardView","tableCard","toggleIcon","classList","contains","add","replace","remove","setAttribute","removeAttribute"],"mappings":"0kBAuBA,uDACA,OACA,OAEA,O,w2BAEMA,CAAAA,CAAO,CAAG,CACZC,SAAS,CAAE,WADC,CAEZC,QAAQ,CAAE,MAFE,CAGZC,MAAM,CAAE,aAHI,CAIZC,QAAQ,CAAE,eAJE,C,CAOZC,CAAW,G,CAOFC,CAAI,CAAG,UAAM,CAEtB,GAAID,CAAJ,CAAiB,CAEb,MACH,CAGDE,QAAQ,CAACC,gBAAT,CAA0BC,CAAY,CAACC,WAAvC,4CAAoD,WAAMC,CAAN,+FAC1CC,CAD0C,CAC1BD,CAAK,CAACE,MAAN,CAAaC,OAAb,CAAqBC,CAAe,CAACC,OAAhB,CAAwBC,MAA7C,CAD0B,MAE1B,IAAlB,GAAAL,CAF4C,mDAM1CM,CAN0C,CAM9BN,CAAa,CAACO,aAAd,CAA4BC,CAAc,CAACC,IAAf,CAAoBC,MAAhD,CAN8B,CAO1CC,CAP0C,CAO7B,WAAAZ,CAAK,CAACa,MAAN,uBAAcC,kBAAd,EAAmC,IAAnC,CAA0C,CAPb,gBAS1C,oBAAcP,CAAd,CAAyBK,CAAzB,KACDG,IADC,CACIC,qBADJ,EAEDC,KAFC,CAEKC,UAAaC,SAFlB,CAT0C,yCAApD,yDAeAvB,QAAQ,CAACC,gBAAT,CAA0B,OAA1B,CAAmC,SAAAG,CAAK,CAAI,CACxC,GAAMoB,CAAAA,CAAiB,CAAGpB,CAAK,CAACE,MAAN,CAAaC,OAAb,CAAqBC,CAAe,CAACiB,OAAhB,CAAwBD,iBAA7C,CAA1B,CACA,GAA0B,IAAtB,GAAAA,CAAJ,CAAgC,CAC5B,MACH,CACDpB,CAAK,CAACsB,cAAN,GACA,GAAMC,CAAAA,CAAW,CAAGC,IAAI,CAACC,KAAL,CAAWL,CAAiB,CAACM,OAAlB,CAA0BH,WAArC,CAApB,CACAI,MAAM,CAACC,SAAP,CAAiB5B,CAAjB,CAAwBuB,CAAW,CAACM,cAApC,CACH,CARD,EAWAjC,QAAQ,CAACC,gBAAT,CAA0B,OAA1B,CAAmC,SAACG,CAAD,CAAW,CAC1C,GAAM8B,CAAAA,CAAU,CAAG9B,CAAK,CAACE,MAAN,CAAaC,OAAb,CAAqBC,CAAe,CAACiB,OAAhB,CAAwBU,cAA7C,CAAnB,CACA,GAAID,CAAJ,CAAgB,IACNE,CAAAA,CAAS,CAAGF,CAAU,CAAC3B,OAAX,CAAmB,IAAnB,CADN,CAEN8B,CAAU,CAAGH,CAAU,CAACtB,aAAX,CAAyB,GAAzB,CAFP,CAGZR,CAAK,CAACsB,cAAN,GACA,GAAIQ,CAAU,CAACI,SAAX,CAAqBC,QAArB,CAA8B9C,CAAO,CAACC,SAAtC,CAAJ,CAAsD,CAClD0C,CAAS,CAACE,SAAV,CAAoBE,GAApB,CAAwB/C,CAAO,CAACE,QAAhC,EACA0C,CAAU,CAACC,SAAX,CAAqBG,OAArB,CAA6BhD,CAAO,CAACI,QAArC,CAA+CJ,CAAO,CAACG,MAAvD,EACAsC,CAAU,CAACI,SAAX,CAAqBI,MAArB,CAA4BjD,CAAO,CAACC,SAApC,EACAwC,CAAU,CAACS,YAAX,CAAwB,eAAxB,CAAyC,MAAzC,CACH,CALD,IAKO,CACHP,CAAS,CAACE,SAAV,CAAoBI,MAApB,CAA2BjD,CAAO,CAACE,QAAnC,EACA0C,CAAU,CAACC,SAAX,CAAqBG,OAArB,CAA6BhD,CAAO,CAACG,MAArC,CAA6CH,CAAO,CAACI,QAArD,EACAqC,CAAU,CAACI,SAAX,CAAqBE,GAArB,CAAyB/C,CAAO,CAACC,SAAjC,EACAwC,CAAU,CAACU,eAAX,CAA2B,eAA3B,CACH,CACJ,CACJ,CAlBD,EAoBA9C,CAAW,GACd,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 .\n\n/**\n * Report builder report management\n *\n * @module core_reportbuilder/report\n * @copyright 2021 Paul Holden \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Notification from 'core/notification';\nimport * as reportEvents from 'core_reportbuilder/local/events';\nimport * as reportSelectors from 'core_reportbuilder/local/selectors';\nimport {setPageNumber, refreshTableContent} from 'core_table/dynamic';\nimport * as tableSelectors from 'core_table/local/dynamic/selectors';\n\nconst CLASSES = {\n COLLAPSED: 'collapsed',\n EXPANDED: 'show',\n ICONUP: 'fa-angle-up',\n ICONDOWN: 'fa-angle-down'\n};\n\nlet initialized = false;\n\n/**\n * Initialise module for given report\n *\n * @method\n */\nexport const init = () => {\n\n if (initialized) {\n // We already added the event listeners (can be called multiple times by mustache template).\n return;\n }\n\n // Listen for the table reload event.\n document.addEventListener(reportEvents.tableReload, async(event) => {\n const reportElement = event.target.closest(reportSelectors.regions.report);\n if (reportElement === null) {\n return;\n }\n\n const tableRoot = reportElement.querySelector(tableSelectors.main.region);\n const pageNumber = event.detail?.preservePagination ? null : 1;\n\n await setPageNumber(tableRoot, pageNumber, false)\n .then(refreshTableContent)\n .catch(Notification.exception);\n });\n\n // Listen for trigger popup events.\n document.addEventListener('click', event => {\n const reportActionPopup = event.target.closest(reportSelectors.actions.reportActionPopup);\n if (reportActionPopup === null) {\n return;\n }\n event.preventDefault();\n const popupAction = JSON.parse(reportActionPopup.dataset.popupAction);\n window.openpopup(event, popupAction.jsfunctionargs);\n });\n\n // Listen for card view toggle events.\n document.addEventListener('click', (event) => {\n const toggleCard = event.target.closest(reportSelectors.actions.toggleCardView);\n if (toggleCard) {\n const tableCard = toggleCard.closest('tr');\n const toggleIcon = toggleCard.querySelector('i');\n event.preventDefault();\n if (toggleCard.classList.contains(CLASSES.COLLAPSED)) {\n tableCard.classList.add(CLASSES.EXPANDED);\n toggleIcon.classList.replace(CLASSES.ICONDOWN, CLASSES.ICONUP);\n toggleCard.classList.remove(CLASSES.COLLAPSED);\n toggleCard.setAttribute('aria-expanded', \"true\");\n } else {\n tableCard.classList.remove(CLASSES.EXPANDED);\n toggleIcon.classList.replace(CLASSES.ICONUP, CLASSES.ICONDOWN);\n toggleCard.classList.add(CLASSES.COLLAPSED);\n toggleCard.removeAttribute('aria-expanded');\n }\n }\n });\n\n initialized = true;\n};\n"],"file":"report.min.js"} \ No newline at end of file diff --git a/reportbuilder/amd/src/report.js b/reportbuilder/amd/src/report.js index 3a69e92a6b1..e98d8a00cca 100644 --- a/reportbuilder/amd/src/report.js +++ b/reportbuilder/amd/src/report.js @@ -21,6 +21,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +import Notification from 'core/notification'; import * as reportEvents from 'core_reportbuilder/local/events'; import * as reportSelectors from 'core_reportbuilder/local/selectors'; import {setPageNumber, refreshTableContent} from 'core_table/dynamic'; @@ -58,7 +59,8 @@ export const init = () => { const pageNumber = event.detail?.preservePagination ? null : 1; await setPageNumber(tableRoot, pageNumber, false) - .then(refreshTableContent); + .then(refreshTableContent) + .catch(Notification.exception); }); // Listen for trigger popup events. diff --git a/reportbuilder/classes/local/aggregation/groupconcat.php b/reportbuilder/classes/local/aggregation/groupconcat.php index dce3dbb41a1..2c1412623fe 100644 --- a/reportbuilder/classes/local/aggregation/groupconcat.php +++ b/reportbuilder/classes/local/aggregation/groupconcat.php @@ -132,11 +132,19 @@ class groupconcat extends base { // Store original names of all values that would be present without aggregation. $valuenames = array_keys($values); - $values = explode(self::FIELD_VALUE_DELIMETER, (string) reset($values)); + $valuenamescount = count($valuenames); // Loop over each extracted value from the concatenated string. + $values = explode(self::FIELD_VALUE_DELIMETER, (string) reset($values)); foreach ($values as $value) { - $originalvalue = array_combine($valuenames, explode(self::COLUMN_FIELD_DELIMETER, $value)); + + // Ensure we have equal number of value names/data, account for truncation by DB. + $valuedata = explode(self::COLUMN_FIELD_DELIMETER, $value); + if ($valuenamescount !== count($valuedata)) { + continue; + } + + $originalvalue = array_combine($valuenames, $valuedata); $originalfirstvalue = reset($originalvalue); // Once we've re-constructed each value, we can apply callbacks to it.