@epcare/esm-report-builder 0.1.1-pre.76 → 0.1.1-pre.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/__mocks__/react-i18next.js +12 -0
  2. package/dist/729.js +1 -1
  3. package/dist/760.js +1 -0
  4. package/dist/760.js.map +1 -0
  5. package/dist/main.js +1 -1
  6. package/dist/openmrs-esm-report-builder.js.buildmanifest.json +26 -26
  7. package/dist/routes.json +1 -1
  8. package/package.json +1 -1
  9. package/routes.json +3 -2
  10. package/src/components/admin/admin-page.component.tsx +53 -24
  11. package/src/components/admin/etl-browser/etl-browser.component.scss +10 -3
  12. package/src/components/admin/etl-browser/preview-grid.component.tsx +1 -1
  13. package/src/components/admin/etl-sources-page.component.tsx +30 -19
  14. package/src/components/admin/report-categories-page.component.tsx +32 -21
  15. package/src/components/admin/report-library-page.component.tsx +30 -19
  16. package/src/components/app-shell/report-builder-shell.component.tsx +194 -162
  17. package/src/components/app-shell/report-builder-shell.scss +4 -1
  18. package/src/components/dashboards/dashboards-page.component.tsx +13 -6
  19. package/src/components/dashboards/dashboards-table.component.tsx +24 -17
  20. package/src/components/data-themes/data-themes-page.component.tsx +11 -4
  21. package/src/components/data-themes/data-themes-table.component.tsx +10 -3
  22. package/src/components/data-visualizer/data-visualizer.resource.ts +49 -37
  23. package/src/components/etl-monitor/builder/etl-monitor-builder-page.component.tsx +6 -1
  24. package/src/components/etl-monitor/etl-monitors-page.component.tsx +35 -24
  25. package/src/components/import-export/import-export-page.component.tsx +38 -22
  26. package/src/components/indicators/indicators-page.component.tsx +41 -6
  27. package/src/components/indicators/indicators-table.component.tsx +24 -4
  28. package/src/components/landing/report-builder-landing-page.component.tsx +34 -1
  29. package/src/components/linelist/definition/linelist-definition-editor.component.tsx +14 -2
  30. package/src/components/linelist/linelist-dashboard.page.component.tsx +20 -13
  31. package/src/components/report/report-dashboard.page.component.tsx +14 -8
  32. package/src/components/report/report-editor.page.component.tsx +6 -1
  33. package/src/components/report-sections/report-sections-page.component.tsx +17 -5
  34. package/src/components/security/access-denied-page.component.tsx +69 -0
  35. package/src/components/security/access-denied-page.scss +39 -0
  36. package/src/components/security/privilege-route.component.test.tsx +79 -0
  37. package/src/components/security/privilege-route.component.tsx +39 -0
  38. package/src/constants/privileges.test.ts +53 -0
  39. package/src/constants/privileges.ts +118 -0
  40. package/src/hooks/use-report-builder-privileges.test.tsx +98 -0
  41. package/src/hooks/use-report-builder-privileges.ts +58 -0
  42. package/src/resources/etl-monitor/etl-monitor-test.api.ts +5 -2
  43. package/src/resources/etl-task/etl-task.api.ts +21 -13
  44. package/src/resources/legacy-reports/legacy-reports.api.ts +10 -22
  45. package/src/resources/openmrs-api.ts +30 -14
  46. package/src/resources/report-section/section-preview.api.ts +10 -6
  47. package/src/routes/report-builder.routes.tsx +93 -28
  48. package/src/routes.json +3 -2
  49. package/src/utils/api-error.utils.test.ts +151 -0
  50. package/src/utils/api-error.utils.ts +131 -0
  51. package/dist/359.js +0 -1
  52. package/dist/359.js.map +0 -1
package/dist/main.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e,r,t,n,o={7729(e,r,t){"use strict";var n=t(2897),o={featureName:"report-builder",moduleName:(n.Type.String,n.Type.String,n.Type.String,n.Type.Array,n.Type.String,n.Type.Array,n.Type.String,"@epcare/esm-report-builder")};(0,n.getAsyncLifecycle)(function(){return Promise.all([t.e(469),t.e(656),t.e(705),t.e(710)]).then(t.bind(t,2710))},o),t(6738),(0,n.getAsyncLifecycle)(function(){return Promise.all([t.e(469),t.e(242),t.e(838),t.e(656),t.e(705),t.e(359)]).then(t.bind(t,8359))},o),(0,n.getAsyncLifecycle)(function(){return Promise.all([t.e(469),t.e(656),t.e(705),t.e(669)]).then(t.bind(t,8669))},o)},6738(e,r,t){var n={"./en.json":[4300,[300]]};function o(e){try{if(!t.o(n,e))return Promise.resolve().then(()=>{var r=new Error("Cannot find module '"+e+"'");throw r.code="MODULE_NOT_FOUND",r})}catch(e){return Promise.reject(e)}var r=n[e],o=r[0];return t.e(r[1][0]).then(()=>t(o))}o.keys=()=>Object.keys(n),o.id=6738,e.exports=o}},a={};function i(e){var r=a[e];if(void 0!==r)return r.exports;var t=a[e]={id:e,exports:{}};return o[e].call(t.exports,t,t.exports,i),t.exports}i.m=o,i.c=a,i.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return i.d(r,{a:r}),r},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,i.t=function(t,n){if(1&n&&(t=this(t)),8&n)return t;if("object"==typeof t&&t){if(4&n&&t.__esModule)return t;if(16&n&&"function"==typeof t.then)return t}var o=Object.create(null);i.r(o);var a={};e=e||[null,r({}),r([]),r(r)];for(var u=2&n&&t;("object"==typeof u||"function"==typeof u)&&!~e.indexOf(u);u=r(u))Object.getOwnPropertyNames(u).forEach(e=>a[e]=()=>t[e]);return a.default=()=>t,i.d(o,a),o},i.d=(e,r)=>{for(var t in r)i.o(r,t)&&!i.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},i.f={},i.e=e=>Promise.all(Object.keys(i.f).reduce((r,t)=>(i.f[t](e,r),r),[])),i.u=e=>e+".js",i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),i.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t={},n="@epcare/esm-report-builder:",i.l=(e,r,o,a)=>{if(t[e])t[e].push(r);else{var u,l;if(void 0!==o)for(var s=document.getElementsByTagName("script"),f=0;f<s.length;f++){var c=s[f];if(c.getAttribute("src")==e||c.getAttribute("data-webpack")==n+o){u=c;break}}u||(l=!0,(u=document.createElement("script")).charset="utf-8",i.nc&&u.setAttribute("nonce",i.nc),u.setAttribute("data-webpack",n+o),u.src=e),t[e]=[r];var p=(r,n)=>{u.onerror=u.onload=null,clearTimeout(d);var o=t[e];if(delete t[e],u.parentNode&&u.parentNode.removeChild(u),o&&o.forEach(e=>e(n)),r)return r(n)},d=setTimeout(p.bind(null,void 0,{type:"timeout",target:u}),12e4);u.onerror=p.bind(null,u.onerror),u.onload=p.bind(null,u.onload),l&&document.head.appendChild(u)}},i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{i.S={};var e={},r={};i.I=(t,n)=>{n||(n=[]);var o=r[t];if(o||(o=r[t]={}),!(n.indexOf(o)>=0)){if(n.push(o),e[t])return e[t];i.o(i.S,t)||(i.S[t]={});var a=i.S[t],u="@epcare/esm-report-builder",l=(e,r,t,n)=>{var o=a[e]=a[e]||{},i=o[r];(!i||!i.loaded&&(!n!=!i.eager?n:u>i.from))&&(o[r]={get:t,from:u,eager:!!n})},s=[];return"default"===t&&(l("@openmrs/esm-framework","9.0.3-pre.4342",()=>Promise.all([i.e(469),i.e(478),i.e(242),i.e(162),i.e(656),i.e(705),i.e(446)]).then(()=>()=>i(2162))),l("react-dom","18.3.1",()=>Promise.all([i.e(961),i.e(656)]).then(()=>()=>i(961))),l("react-i18next","16.6.6",()=>Promise.all([i.e(478),i.e(311),i.e(656)]).then(()=>()=>i(3311))),l("react","18.3.1",()=>i.e(540).then(()=>()=>i(6540))),l("rxjs","6.6.7",()=>i.e(184).then(()=>()=>i(3184))),l("single-spa","5.9.5",()=>i.e(917).then(()=>()=>i(7917)))),e[t]=s.length?Promise.all(s).then(()=>e[t]=1):1}}})(),(()=>{var e;i.g.importScripts&&(e=i.g.location+"");var r=i.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),i.p=e})(),(()=>{var e=e=>{var r=e=>e.split(".").map(e=>+e==e?+e:e),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},r=e=>{var t=e[0],n="";if(1===e.length)return"*";if(t+.5){n+=0==t?">=":-1==t?"<":1==t?"^":2==t?"~":t>0?"=":"!=";for(var o=1,a=1;a<e.length;a++)o--,n+="u"==(typeof(u=e[a]))[0]?"-":(o>0?".":"")+(o=2,u);return n}var i=[];for(a=1;a<e.length;a++){var u=e[a];i.push(0===u?"not("+l()+")":1===u?"("+l()+" || "+l()+")":2===u?i.pop()+" "+i.pop():r(u))}return l();function l(){return i.pop().replace(/^\((.+)\)$/,"$1")}},t=(r,n)=>{if(0 in r){n=e(n);var o=r[0],a=o<0;a&&(o=-o-1);for(var i=0,u=1,l=!0;;u++,i++){var s,f,c=u<r.length?(typeof r[u])[0]:"";if(i>=n.length||"o"==(f=(typeof(s=n[i]))[0]))return!l||("u"==c?u>o&&!a:""==c!=a);if("u"==f){if(!l||"u"!=c)return!1}else if(l)if(c==f)if(u<=o){if(s!=r[u])return!1}else{if(a?s>r[u]:s<r[u])return!1;s!=r[u]&&(l=!1)}else if("s"!=c&&"n"!=c){if(a||u<=o)return!1;l=!1,u--}else{if(u<=o||f<c!=a)return!1;l=!1}else"s"!=c&&"n"!=c&&(l=!1,u--)}}var p=[],d=p.pop.bind(p);for(i=1;i<r.length;i++){var h=r[i];p.push(1==h?d()|d():2==h?d()&d():h?t(h,n):!d())}return!!d()},n=(r,t,n)=>{var o=n?(e=>Object.keys(e).reduce((r,t)=>(e[t].eager&&(r[t]=e[t]),r),{}))(r[t]):r[t];return Object.keys(o).reduce((r,t)=>!r||!o[r].loaded&&((r,t)=>{r=e(r),t=e(t);for(var n=0;;){if(n>=r.length)return n<t.length&&"u"!=(typeof t[n])[0];var o=r[n],a=(typeof o)[0];if(n>=t.length)return"u"==a;var i=t[n],u=(typeof i)[0];if(a!=u)return"o"==a&&"n"==u||"s"==u||"u"==a;if("o"!=a&&"u"!=a&&o!=i)return o<i;n++}})(r,t)?t:r,0)},o=(e,r,t)=>t?t():((e,r)=>(e=>{throw new Error(e)})("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),a=(e=>function(r,t,n,o,a){var u=i.I(r);return u&&u.then&&!n?u.then(e.bind(e,r,i.S[r],t,!1,o,a)):e(r,i.S[r],t,n,o,a)})((e,a,u,l,s,f)=>{if(!((e,r)=>e&&i.o(e,r))(a,u))return o(e,u,f);var c,p,d=n(a,u,l);return t(s,d)||(p=((e,t,n,o)=>"Unsatisfied version "+n+" from "+(n&&e[t][n].from)+" of shared singleton module "+t+" (required "+r(o)+")")(a,u,d,s),"undefined"!=typeof console&&console.warn&&console.warn(p)),(c=a[u][d]).loaded=1,c.get()}),u={},l={2897:()=>a("default","@openmrs/esm-framework",!1,[1,8,0,0],()=>Promise.all([i.e(469),i.e(478),i.e(242),i.e(162),i.e(656),i.e(705),i.e(446)]).then(()=>()=>i(2162))),7656:()=>a("default","react",!1,[1,18,0,0],()=>i.e(540).then(()=>()=>i(6540))),1180:()=>a("default","react-i18next",!1,[1,16,0,0],()=>Promise.all([i.e(478),i.e(311)]).then(()=>()=>i(3311))),5686:()=>a("default","react-dom",!1,[1,18,0,0],()=>i.e(961).then(()=>()=>i(961))),7858:()=>a("default","rxjs",!1,[1,6,6,7],()=>i.e(184).then(()=>()=>i(3184))),8443:()=>a("default","single-spa",!1,[1,5,0,0],()=>i.e(917).then(()=>()=>i(7917)))};[2897].forEach(e=>{i.m[e]=r=>{u[e]=0,delete i.c[e];var t=l[e]();if("function"!=typeof t)throw new Error("Shared module is not available for eager consumption: "+e);r.exports=t()}});var s={446:[7858,8443],656:[7656],705:[1180,5686],792:[2897]},f={};i.f.consumes=(e,r)=>{i.o(s,e)&&s[e].forEach(e=>{if(i.o(u,e))return r.push(u[e]);if(!f[e]){var t=r=>{u[e]=0,i.m[e]=t=>{delete i.c[e],t.exports=r()}};f[e]=!0;var n=r=>{delete u[e],i.m[e]=t=>{throw delete i.c[e],r}};try{var o=l[e]();o.then?r.push(u[e]=o.then(t).catch(n)):t(o)}catch(e){n(e)}}})}})(),(()=>{var e={729:0,792:0};i.f.j=(r,t)=>{var n=i.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else if(/^(446|656|705)$/.test(r))e[r]=0;else{var o=new Promise((t,o)=>n=e[r]=[t,o]);t.push(n[2]=o);var a=i.p+i.u(r),u=new Error;i.l(a,t=>{if(i.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var o=t&&("load"===t.type?"missing":t.type),a=t&&t.target&&t.target.src;u.message="Loading chunk "+r+" failed.\n("+o+": "+a+")",u.name="ChunkLoadError",u.type=o,u.request=a,n[1](u)}},"chunk-"+r,r)}};var r=(r,t)=>{var n,o,[a,u,l]=t,s=0;if(a.some(r=>0!==e[r])){for(n in u)i.o(u,n)&&(i.m[n]=u[n]);l&&l(i)}for(r&&r(t);s<a.length;s++)o=a[s],i.o(e,o)&&e[o]&&e[o][0](),e[o]=0},t=self.webpackChunk_epcare_esm_report_builder=self.webpackChunk_epcare_esm_report_builder||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),i.nc=void 0,i(7729)})();
1
+ (()=>{var e,r,t,n,o={7729(e,r,t){"use strict";var n=t(2897),o={featureName:"report-builder",moduleName:(n.Type.String,n.Type.String,n.Type.String,n.Type.Array,n.Type.String,n.Type.Array,n.Type.String,"@epcare/esm-report-builder")};(0,n.getAsyncLifecycle)(function(){return Promise.all([t.e(469),t.e(656),t.e(705),t.e(710)]).then(t.bind(t,2710))},o),t(6738),(0,n.getAsyncLifecycle)(function(){return Promise.all([t.e(469),t.e(242),t.e(838),t.e(656),t.e(705),t.e(760)]).then(t.bind(t,2760))},o),(0,n.getAsyncLifecycle)(function(){return Promise.all([t.e(469),t.e(656),t.e(705),t.e(669)]).then(t.bind(t,8669))},o)},6738(e,r,t){var n={"./en.json":[4300,[300]]};function o(e){try{if(!t.o(n,e))return Promise.resolve().then(()=>{var r=new Error("Cannot find module '"+e+"'");throw r.code="MODULE_NOT_FOUND",r})}catch(e){return Promise.reject(e)}var r=n[e],o=r[0];return t.e(r[1][0]).then(()=>t(o))}o.keys=()=>Object.keys(n),o.id=6738,e.exports=o}},a={};function i(e){var r=a[e];if(void 0!==r)return r.exports;var t=a[e]={id:e,exports:{}};return o[e].call(t.exports,t,t.exports,i),t.exports}i.m=o,i.c=a,i.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return i.d(r,{a:r}),r},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,i.t=function(t,n){if(1&n&&(t=this(t)),8&n)return t;if("object"==typeof t&&t){if(4&n&&t.__esModule)return t;if(16&n&&"function"==typeof t.then)return t}var o=Object.create(null);i.r(o);var a={};e=e||[null,r({}),r([]),r(r)];for(var u=2&n&&t;("object"==typeof u||"function"==typeof u)&&!~e.indexOf(u);u=r(u))Object.getOwnPropertyNames(u).forEach(e=>a[e]=()=>t[e]);return a.default=()=>t,i.d(o,a),o},i.d=(e,r)=>{for(var t in r)i.o(r,t)&&!i.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},i.f={},i.e=e=>Promise.all(Object.keys(i.f).reduce((r,t)=>(i.f[t](e,r),r),[])),i.u=e=>e+".js",i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),i.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t={},n="@epcare/esm-report-builder:",i.l=(e,r,o,a)=>{if(t[e])t[e].push(r);else{var u,l;if(void 0!==o)for(var s=document.getElementsByTagName("script"),f=0;f<s.length;f++){var c=s[f];if(c.getAttribute("src")==e||c.getAttribute("data-webpack")==n+o){u=c;break}}u||(l=!0,(u=document.createElement("script")).charset="utf-8",i.nc&&u.setAttribute("nonce",i.nc),u.setAttribute("data-webpack",n+o),u.src=e),t[e]=[r];var p=(r,n)=>{u.onerror=u.onload=null,clearTimeout(d);var o=t[e];if(delete t[e],u.parentNode&&u.parentNode.removeChild(u),o&&o.forEach(e=>e(n)),r)return r(n)},d=setTimeout(p.bind(null,void 0,{type:"timeout",target:u}),12e4);u.onerror=p.bind(null,u.onerror),u.onload=p.bind(null,u.onload),l&&document.head.appendChild(u)}},i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{i.S={};var e={},r={};i.I=(t,n)=>{n||(n=[]);var o=r[t];if(o||(o=r[t]={}),!(n.indexOf(o)>=0)){if(n.push(o),e[t])return e[t];i.o(i.S,t)||(i.S[t]={});var a=i.S[t],u="@epcare/esm-report-builder",l=(e,r,t,n)=>{var o=a[e]=a[e]||{},i=o[r];(!i||!i.loaded&&(!n!=!i.eager?n:u>i.from))&&(o[r]={get:t,from:u,eager:!!n})},s=[];return"default"===t&&(l("@openmrs/esm-framework","9.0.3-pre.4342",()=>Promise.all([i.e(469),i.e(478),i.e(242),i.e(162),i.e(656),i.e(705),i.e(446)]).then(()=>()=>i(2162))),l("react-dom","18.3.1",()=>Promise.all([i.e(961),i.e(656)]).then(()=>()=>i(961))),l("react-i18next","16.6.6",()=>Promise.all([i.e(478),i.e(311),i.e(656)]).then(()=>()=>i(3311))),l("react","18.3.1",()=>i.e(540).then(()=>()=>i(6540))),l("rxjs","6.6.7",()=>i.e(184).then(()=>()=>i(3184))),l("single-spa","5.9.5",()=>i.e(917).then(()=>()=>i(7917)))),e[t]=s.length?Promise.all(s).then(()=>e[t]=1):1}}})(),(()=>{var e;i.g.importScripts&&(e=i.g.location+"");var r=i.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),i.p=e})(),(()=>{var e=e=>{var r=e=>e.split(".").map(e=>+e==e?+e:e),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},r=e=>{var t=e[0],n="";if(1===e.length)return"*";if(t+.5){n+=0==t?">=":-1==t?"<":1==t?"^":2==t?"~":t>0?"=":"!=";for(var o=1,a=1;a<e.length;a++)o--,n+="u"==(typeof(u=e[a]))[0]?"-":(o>0?".":"")+(o=2,u);return n}var i=[];for(a=1;a<e.length;a++){var u=e[a];i.push(0===u?"not("+l()+")":1===u?"("+l()+" || "+l()+")":2===u?i.pop()+" "+i.pop():r(u))}return l();function l(){return i.pop().replace(/^\((.+)\)$/,"$1")}},t=(r,n)=>{if(0 in r){n=e(n);var o=r[0],a=o<0;a&&(o=-o-1);for(var i=0,u=1,l=!0;;u++,i++){var s,f,c=u<r.length?(typeof r[u])[0]:"";if(i>=n.length||"o"==(f=(typeof(s=n[i]))[0]))return!l||("u"==c?u>o&&!a:""==c!=a);if("u"==f){if(!l||"u"!=c)return!1}else if(l)if(c==f)if(u<=o){if(s!=r[u])return!1}else{if(a?s>r[u]:s<r[u])return!1;s!=r[u]&&(l=!1)}else if("s"!=c&&"n"!=c){if(a||u<=o)return!1;l=!1,u--}else{if(u<=o||f<c!=a)return!1;l=!1}else"s"!=c&&"n"!=c&&(l=!1,u--)}}var p=[],d=p.pop.bind(p);for(i=1;i<r.length;i++){var h=r[i];p.push(1==h?d()|d():2==h?d()&d():h?t(h,n):!d())}return!!d()},n=(r,t,n)=>{var o=n?(e=>Object.keys(e).reduce((r,t)=>(e[t].eager&&(r[t]=e[t]),r),{}))(r[t]):r[t];return Object.keys(o).reduce((r,t)=>!r||!o[r].loaded&&((r,t)=>{r=e(r),t=e(t);for(var n=0;;){if(n>=r.length)return n<t.length&&"u"!=(typeof t[n])[0];var o=r[n],a=(typeof o)[0];if(n>=t.length)return"u"==a;var i=t[n],u=(typeof i)[0];if(a!=u)return"o"==a&&"n"==u||"s"==u||"u"==a;if("o"!=a&&"u"!=a&&o!=i)return o<i;n++}})(r,t)?t:r,0)},o=(e,r,t)=>t?t():((e,r)=>(e=>{throw new Error(e)})("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),a=(e=>function(r,t,n,o,a){var u=i.I(r);return u&&u.then&&!n?u.then(e.bind(e,r,i.S[r],t,!1,o,a)):e(r,i.S[r],t,n,o,a)})((e,a,u,l,s,f)=>{if(!((e,r)=>e&&i.o(e,r))(a,u))return o(e,u,f);var c,p,d=n(a,u,l);return t(s,d)||(p=((e,t,n,o)=>"Unsatisfied version "+n+" from "+(n&&e[t][n].from)+" of shared singleton module "+t+" (required "+r(o)+")")(a,u,d,s),"undefined"!=typeof console&&console.warn&&console.warn(p)),(c=a[u][d]).loaded=1,c.get()}),u={},l={2897:()=>a("default","@openmrs/esm-framework",!1,[1,8,0,0],()=>Promise.all([i.e(469),i.e(478),i.e(242),i.e(162),i.e(656),i.e(705),i.e(446)]).then(()=>()=>i(2162))),7656:()=>a("default","react",!1,[1,18,0,0],()=>i.e(540).then(()=>()=>i(6540))),1180:()=>a("default","react-i18next",!1,[1,16,0,0],()=>Promise.all([i.e(478),i.e(311)]).then(()=>()=>i(3311))),5686:()=>a("default","react-dom",!1,[1,18,0,0],()=>i.e(961).then(()=>()=>i(961))),7858:()=>a("default","rxjs",!1,[1,6,6,7],()=>i.e(184).then(()=>()=>i(3184))),8443:()=>a("default","single-spa",!1,[1,5,0,0],()=>i.e(917).then(()=>()=>i(7917)))};[2897].forEach(e=>{i.m[e]=r=>{u[e]=0,delete i.c[e];var t=l[e]();if("function"!=typeof t)throw new Error("Shared module is not available for eager consumption: "+e);r.exports=t()}});var s={446:[7858,8443],656:[7656],705:[1180,5686],792:[2897]},f={};i.f.consumes=(e,r)=>{i.o(s,e)&&s[e].forEach(e=>{if(i.o(u,e))return r.push(u[e]);if(!f[e]){var t=r=>{u[e]=0,i.m[e]=t=>{delete i.c[e],t.exports=r()}};f[e]=!0;var n=r=>{delete u[e],i.m[e]=t=>{throw delete i.c[e],r}};try{var o=l[e]();o.then?r.push(u[e]=o.then(t).catch(n)):t(o)}catch(e){n(e)}}})}})(),(()=>{var e={729:0,792:0};i.f.j=(r,t)=>{var n=i.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else if(/^(446|656|705)$/.test(r))e[r]=0;else{var o=new Promise((t,o)=>n=e[r]=[t,o]);t.push(n[2]=o);var a=i.p+i.u(r),u=new Error;i.l(a,t=>{if(i.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var o=t&&("load"===t.type?"missing":t.type),a=t&&t.target&&t.target.src;u.message="Loading chunk "+r+" failed.\n("+o+": "+a+")",u.name="ChunkLoadError",u.type=o,u.request=a,n[1](u)}},"chunk-"+r,r)}};var r=(r,t)=>{var n,o,[a,u,l]=t,s=0;if(a.some(r=>0!==e[r])){for(n in u)i.o(u,n)&&(i.m[n]=u[n]);l&&l(i)}for(r&&r(t);s<a.length;s++)o=a[s],i.o(e,o)&&e[o]&&e[o][0](),e[o]=0},t=self.webpackChunk_epcare_esm_report_builder=self.webpackChunk_epcare_esm_report_builder||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),i.nc=void 0,i(7729)})();
@@ -130,30 +130,6 @@
130
130
  "hash": "0e359dbd7feccb45",
131
131
  "childrenByOrder": {}
132
132
  },
133
- {
134
- "rendered": true,
135
- "initial": false,
136
- "entry": false,
137
- "recorded": false,
138
- "size": 3894038,
139
- "sizes": {
140
- "javascript": 3894038
141
- },
142
- "names": [],
143
- "idHints": [],
144
- "runtime": [
145
- "@epcare/esm-report-builder",
146
- "main"
147
- ],
148
- "files": [
149
- "359.js"
150
- ],
151
- "auxiliaryFiles": [
152
- "359.js.map"
153
- ],
154
- "hash": "4349902a4919b40d",
155
- "childrenByOrder": {}
156
- },
157
133
  {
158
134
  "rendered": false,
159
135
  "initial": false,
@@ -414,7 +390,31 @@
414
390
  "auxiliaryFiles": [
415
391
  "729.js.map"
416
392
  ],
417
- "hash": "f7a70c5bd8e8eb33",
393
+ "hash": "806243addf9e6fbd",
394
+ "childrenByOrder": {}
395
+ },
396
+ {
397
+ "rendered": true,
398
+ "initial": false,
399
+ "entry": false,
400
+ "recorded": false,
401
+ "size": 3975691,
402
+ "sizes": {
403
+ "javascript": 3975691
404
+ },
405
+ "names": [],
406
+ "idHints": [],
407
+ "runtime": [
408
+ "@epcare/esm-report-builder",
409
+ "main"
410
+ ],
411
+ "files": [
412
+ "760.js"
413
+ ],
414
+ "auxiliaryFiles": [
415
+ "760.js.map"
416
+ ],
417
+ "hash": "91c8580ce54e48d8",
418
418
  "childrenByOrder": {}
419
419
  },
420
420
  {
@@ -442,7 +442,7 @@
442
442
  "auxiliaryFiles": [
443
443
  "main.js.map"
444
444
  ],
445
- "hash": "94ce4351bf122a59",
445
+ "hash": "dd19761663af2d04",
446
446
  "childrenByOrder": {}
447
447
  },
448
448
  {
package/dist/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","pages":[{"component":"root","route":"report-builder","online":true,"offline":false,"order":1}],"extensions":[{"name":"system-administration-report-builder-card-link","slot":"system-admin-page-card-link-slot","component":"reportBuilderAdminLink","online":true,"offline":false},{"component":"confirmModal","name":"confirm-modal","online":true,"offline":true}],"version":"0.1.1-pre.76"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","pages":[{"component":"root","route":"report-builder","online":true,"offline":false,"order":1}],"extensions":[{"name":"system-administration-report-builder-card-link","slot":"system-admin-page-card-link-slot","component":"reportBuilderAdminLink","online":true,"offline":false,"privileges":"Task: reportbuilder.report.view"},{"component":"confirmModal","name":"confirm-modal","online":true,"offline":true}],"version":"0.1.1-pre.78"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epcare/esm-report-builder",
3
- "version": "0.1.1-pre.76",
3
+ "version": "0.1.1-pre.78",
4
4
  "license": "MPL-2.0",
5
5
  "description": "OpenMRS ESM Report Builder",
6
6
  "browser": "dist/openmrs-esm-report-builder.js",
package/routes.json CHANGED
@@ -15,7 +15,8 @@
15
15
  "slot": "system-admin-page-card-link-slot",
16
16
  "component": "reportBuilderAdminLink",
17
17
  "online": true,
18
- "offline": false
18
+ "offline": false,
19
+ "privileges": "Task: reportbuilder.report.view"
19
20
  }
20
21
  ]
21
- }
22
+ }
@@ -1,12 +1,49 @@
1
1
  import React from 'react';
2
- import { ClickableTile, Stack } from '@carbon/react';
2
+ import { ClickableTile, InlineNotification, Stack } from '@carbon/react';
3
3
  import { useNavigate } from 'react-router-dom';
4
4
  import Header from '../shared/header/header.component';
5
+ import { RB } from '../../constants/privileges';
6
+ import { useReportBuilderPrivileges } from '../../hooks/use-report-builder-privileges';
5
7
 
6
8
  const tileStyle: React.CSSProperties = { minHeight: '10rem' };
7
9
 
8
10
  export default function AdminPage() {
9
11
  const navigate = useNavigate();
12
+ const { has } = useReportBuilderPrivileges();
13
+
14
+ const tiles = [
15
+ {
16
+ path: '/admin/report-library',
17
+ title: 'Report Library',
18
+ body: 'Catalog completed and legacy reports before full migration into the builder.',
19
+ required: [RB.LIBRARY_VIEW],
20
+ },
21
+ {
22
+ path: '/admin/themes',
23
+ title: 'Data Themes',
24
+ body: 'Manage reusable source configurations and table mappings.',
25
+ required: [RB.THEME_VIEW],
26
+ },
27
+ {
28
+ path: '/admin/etl-tasks',
29
+ title: 'ETL Tasks',
30
+ body: 'Configure and run scheduled ETL processes for data extraction and transformation.',
31
+ required: [RB.PACKAGE_IMPORT],
32
+ },
33
+ {
34
+ path: '/admin/etl-browser',
35
+ title: 'ETL Data Browser',
36
+ body: 'Explore ETL schemas, tables, columns, and sample records.',
37
+ required: [RB.ETLSOURCE_VIEW],
38
+ },
39
+ {
40
+ path: '/admin/dashboards',
41
+ title: 'Dashboards',
42
+ body: 'Configure dashboards composed of sections and widgets (ETL monitors, reports).',
43
+ required: [RB.DASHBOARD_VIEW],
44
+ },
45
+ ];
46
+ const visibleTiles = tiles.filter((tile) => has(...tile.required));
10
47
 
11
48
  return (
12
49
  <Stack gap={5}>
@@ -16,30 +53,22 @@ export default function AdminPage() {
16
53
  />
17
54
 
18
55
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: '1rem' }}>
19
- <ClickableTile style={tileStyle} onClick={() => navigate('/admin/report-library')}>
20
- <h4>Report Library</h4>
21
- <p>Catalog completed and legacy reports before full migration into the builder.</p>
22
- </ClickableTile>
23
-
24
- <ClickableTile style={tileStyle} onClick={() => navigate('/admin/themes')}>
25
- <h4>Data Themes</h4>
26
- <p>Manage reusable source configurations and table mappings.</p>
27
- </ClickableTile>
28
-
29
- <ClickableTile style={tileStyle} onClick={() => navigate('/admin/etl-tasks')}>
30
- <h4>ETL Tasks</h4>
31
- <p>Configure and run scheduled ETL processes for data extraction and transformation.</p>
32
- </ClickableTile>
33
-
34
- <ClickableTile style={tileStyle} onClick={() => navigate('/admin/etl-browser')}>
35
- <h4>ETL Data Browser</h4>
36
- <p>Explore ETL schemas, tables, columns, and sample records.</p>
37
- </ClickableTile>
56
+ {visibleTiles.map((tile) => (
57
+ <ClickableTile key={tile.path} style={tileStyle} onClick={() => navigate(tile.path)}>
58
+ <h4>{tile.title}</h4>
59
+ <p>{tile.body}</p>
60
+ </ClickableTile>
61
+ ))}
38
62
 
39
- <ClickableTile style={tileStyle} onClick={() => navigate('/admin/dashboards')}>
40
- <h4>Dashboards</h4>
41
- <p>Configure dashboards composed of sections and widgets (ETL monitors, reports).</p>
42
- </ClickableTile>
63
+ {visibleTiles.length === 0 && (
64
+ <InlineNotification
65
+ lowContrast
66
+ kind="info"
67
+ title="No access"
68
+ subtitle="You do not have access to any Report Builder administration features. Contact your administrator."
69
+ hideCloseButton
70
+ />
71
+ )}
43
72
  </div>
44
73
  </Stack>
45
74
  );
@@ -7,6 +7,10 @@
7
7
  /* Bounded height so the side panes scroll internally instead of stretching the page */
8
8
  height: calc(100vh - 16rem);
9
9
  min-height: 30rem;
10
+ /* Flex item of the page Stack: without an explicit floor reset, min-content width
11
+ (driven by wide preview tables) would inflate this row and the shell with it */
12
+ min-width: 0;
13
+ max-width: 100%;
10
14
  }
11
15
 
12
16
  /* Width-controlled wrapper for the draggable/collapsible panes */
@@ -267,8 +271,9 @@
267
271
  flex: 1;
268
272
  min-height: 0;
269
273
  padding: 0.75rem 1rem 1rem;
270
- /* Both axes scroll here so nothing inside can push the page sideways */
271
- overflow: auto;
274
+ /* Vertical scroll only — horizontal overflow belongs to .gridScroll below */
275
+ overflow-y: auto;
276
+ overflow-x: hidden;
272
277
  }
273
278
 
274
279
  /* Toolbar (preview + tabs) */
@@ -297,9 +302,11 @@
297
302
 
298
303
  /* Preview grid — the ONLY element that scrolls horizontally */
299
304
  .gridScroll {
305
+ width: 100%;
300
306
  max-width: 100%;
301
307
  max-height: min(60vh, 34rem);
302
- overflow: auto;
308
+ overflow-x: auto;
309
+ overflow-y: auto;
303
310
  border: 1px solid var(--cds-border-subtle, #dcdcdc);
304
311
 
305
312
  /* Keep columns at natural width so wide tables scroll inside this container */
@@ -89,7 +89,7 @@ export default function PreviewGrid({ table, data, loading, error, onRefresh }:
89
89
  </Button>
90
90
  </div>
91
91
  <p className={styles.truncateNote}>
92
- Preview needs the &quot;View Reports&quot; privilege and a valid table name.
92
+ Preview needs the &quot;sql.execute&quot; privilege and a valid table name.
93
93
  </p>
94
94
  </div>
95
95
  );
@@ -22,6 +22,8 @@ import {
22
22
  } from '@carbon/react';
23
23
  import { Add, Edit, TrashCan } from '@carbon/icons-react';
24
24
  import Header from '../shared/header/header.component';
25
+ import { RB } from '../../constants/privileges';
26
+ import { useReportBuilderPrivileges } from '../../hooks/use-report-builder-privileges';
25
27
  import {
26
28
  createETLSource,
27
29
  deleteETLSource,
@@ -61,6 +63,9 @@ const emptyForm: FormState = {
61
63
  };
62
64
 
63
65
  export default function ETLSourcesPage() {
66
+ const { has: hasPrivilege } = useReportBuilderPrivileges();
67
+ const canEditSource = hasPrivilege(RB.ETLSOURCE_ADD, RB.ETLSOURCE_EDIT);
68
+ const canDeleteSource = hasPrivilege(RB.ETLSOURCE_PURGE);
64
69
  const [q, setQ] = React.useState('');
65
70
  const [rows, setRows] = React.useState<ETLSourceDto[]>([]);
66
71
  const [loading, setLoading] = React.useState(false);
@@ -176,9 +181,11 @@ export default function ETLSourcesPage() {
176
181
  title="ETL Sources"
177
182
  subtitle="Manage ETL source definitions used by the report builder."
178
183
  actions={
179
- <Button data-testid="etl-source-new" size="sm" renderIcon={Add} onClick={openCreate}>
180
- New ETL Source
181
- </Button>
184
+ canEditSource ? (
185
+ <Button data-testid="etl-source-new" size="sm" renderIcon={Add} onClick={openCreate}>
186
+ New ETL Source
187
+ </Button>
188
+ ) : undefined
182
189
  }
183
190
  />
184
191
 
@@ -228,22 +235,26 @@ export default function ETLSourcesPage() {
228
235
  </TableCell>
229
236
  <TableCell>
230
237
  <div style={{ display: 'flex', gap: '0.5rem' }}>
231
- <Button
232
- kind="ghost"
233
- size="sm"
234
- renderIcon={Edit}
235
- iconDescription="Edit"
236
- hasIconOnly
237
- onClick={() => original && openEdit(original)}
238
- />
239
- <Button
240
- kind="ghost"
241
- size="sm"
242
- renderIcon={TrashCan}
243
- iconDescription="Retire"
244
- hasIconOnly
245
- onClick={() => original && onDelete(original)}
246
- />
238
+ {canEditSource && (
239
+ <Button
240
+ kind="ghost"
241
+ size="sm"
242
+ renderIcon={Edit}
243
+ iconDescription="Edit"
244
+ hasIconOnly
245
+ onClick={() => original && openEdit(original)}
246
+ />
247
+ )}
248
+ {canDeleteSource && (
249
+ <Button
250
+ kind="ghost"
251
+ size="sm"
252
+ renderIcon={TrashCan}
253
+ iconDescription="Retire"
254
+ hasIconOnly
255
+ onClick={() => original && onDelete(original)}
256
+ />
257
+ )}
247
258
  </div>
248
259
  </TableCell>
249
260
  </TableRow>
@@ -21,6 +21,8 @@ import {
21
21
  } from '@carbon/react';
22
22
  import { Add, Edit, TrashCan } from '@carbon/icons-react';
23
23
  import Header from '../shared/header/header.component';
24
+ import { RB } from '../../constants/privileges';
25
+ import { useReportBuilderPrivileges } from '../../hooks/use-report-builder-privileges';
24
26
  import {
25
27
  createReportCategory,
26
28
  deleteReportCategory,
@@ -44,6 +46,9 @@ const headers: DataTableHeader[] = [
44
46
  const emptyForm: FormState = { name: '', description: '' };
45
47
 
46
48
  const ReportCategoriesPage: React.FC = () => {
49
+ const { has: hasPrivilege } = useReportBuilderPrivileges();
50
+ const canAddCategory = hasPrivilege(RB.CATEGORY_ADD, RB.CATEGORY_EDIT);
51
+ const canDeleteCategory = hasPrivilege(RB.CATEGORY_PURGE);
47
52
  const [q, setQ] = React.useState('');
48
53
  const [rows, setRows] = React.useState<ReportCategoryDto[]>([]);
49
54
  const [loading, setLoading] = React.useState(false);
@@ -142,9 +147,11 @@ const ReportCategoriesPage: React.FC = () => {
142
147
  title="Report Categories"
143
148
  subtitle="Manage shared categories used to classify reports across the builder."
144
149
  actions={
145
- <Button size="sm" renderIcon={Add} onClick={openCreate}>
146
- New Category
147
- </Button>
150
+ canAddCategory ? (
151
+ <Button size="sm" renderIcon={Add} onClick={openCreate}>
152
+ New Category
153
+ </Button>
154
+ ) : undefined
148
155
  }
149
156
  />
150
157
 
@@ -189,24 +196,28 @@ const ReportCategoriesPage: React.FC = () => {
189
196
  </TableCell>
190
197
  <TableCell>
191
198
  <div style={{ display: 'flex', gap: '0.5rem' }}>
192
- <Button
193
- kind="ghost"
194
- size="sm"
195
- renderIcon={Edit}
196
- iconDescription="Edit"
197
- onClick={() => source && openEdit(source)}
198
- >
199
- Edit
200
- </Button>
201
- <Button
202
- kind="ghost"
203
- size="sm"
204
- renderIcon={TrashCan}
205
- iconDescription="Retire"
206
- onClick={() => source && onDelete(source)}
207
- >
208
- Retire
209
- </Button>
199
+ {canAddCategory && (
200
+ <Button
201
+ kind="ghost"
202
+ size="sm"
203
+ renderIcon={Edit}
204
+ iconDescription="Edit"
205
+ onClick={() => source && openEdit(source)}
206
+ >
207
+ Edit
208
+ </Button>
209
+ )}
210
+ {canDeleteCategory && (
211
+ <Button
212
+ kind="ghost"
213
+ size="sm"
214
+ renderIcon={TrashCan}
215
+ iconDescription="Retire"
216
+ onClick={() => source && onDelete(source)}
217
+ >
218
+ Retire
219
+ </Button>
220
+ )}
210
221
  </div>
211
222
  </TableCell>
212
223
  </TableRow>
@@ -24,6 +24,8 @@ import {
24
24
  } from '@carbon/react';
25
25
  import { Add, Edit, TrashCan } from '@carbon/icons-react';
26
26
  import Header from '../shared/header/header.component';
27
+ import { RB } from '../../constants/privileges';
28
+ import { useReportBuilderPrivileges } from '../../hooks/use-report-builder-privileges';
27
29
  import {
28
30
  createReportLibrary,
29
31
  deleteReportLibrary,
@@ -91,6 +93,9 @@ function categoryDisplayOf(value: ReportLibraryDto['category']): string {
91
93
  }
92
94
 
93
95
  export default function ReportLibraryPage() {
96
+ const { has: hasPrivilege } = useReportBuilderPrivileges();
97
+ const canAddLibrary = hasPrivilege(RB.LIBRARY_ADD, RB.LIBRARY_EDIT);
98
+ const canDeleteLibrary = hasPrivilege(RB.LIBRARY_PURGE);
94
99
  const [q, setQ] = React.useState('');
95
100
  const [rows, setRows] = React.useState<ReportLibraryDto[]>([]);
96
101
  const [categories, setCategories] = React.useState<ReportCategoryDto[]>([]);
@@ -344,9 +349,11 @@ export default function ReportLibraryPage() {
344
349
  Clear
345
350
  </Button>
346
351
 
347
- <Button size="md" renderIcon={Add} onClick={openCreate}>
348
- New Library Entry
349
- </Button>
352
+ {canAddLibrary && (
353
+ <Button size="md" renderIcon={Add} onClick={openCreate}>
354
+ New Library Entry
355
+ </Button>
356
+ )}
350
357
  </div>
351
358
 
352
359
  {error ? <InlineNotification lowContrast kind="error" title="Error" subtitle={error} /> : null}
@@ -396,22 +403,26 @@ export default function ReportLibraryPage() {
396
403
  </TableCell>
397
404
  <TableCell>
398
405
  <div style={{ display: 'flex', gap: '0.5rem' }}>
399
- <Button
400
- kind="ghost"
401
- size="sm"
402
- renderIcon={Edit}
403
- onClick={() => source && openEdit(source)}
404
- >
405
- Edit
406
- </Button>
407
- <Button
408
- kind="ghost"
409
- size="sm"
410
- renderIcon={TrashCan}
411
- onClick={() => source && onDelete(source)}
412
- >
413
- Retire
414
- </Button>
406
+ {canAddLibrary && (
407
+ <Button
408
+ kind="ghost"
409
+ size="sm"
410
+ renderIcon={Edit}
411
+ onClick={() => source && openEdit(source)}
412
+ >
413
+ Edit
414
+ </Button>
415
+ )}
416
+ {canDeleteLibrary && (
417
+ <Button
418
+ kind="ghost"
419
+ size="sm"
420
+ renderIcon={TrashCan}
421
+ onClick={() => source && onDelete(source)}
422
+ >
423
+ Retire
424
+ </Button>
425
+ )}
415
426
  </div>
416
427
  </TableCell>
417
428
  </TableRow>