@ampath/esm-reports-app 1.0.0-next.63 → 1.0.0-next.64

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 (51) hide show
  1. package/dist/299.js +2 -0
  2. package/dist/299.js.LICENSE.txt +3 -0
  3. package/dist/299.js.map +1 -0
  4. package/dist/354.js +2 -0
  5. package/dist/354.js.LICENSE.txt +20 -0
  6. package/dist/354.js.map +1 -0
  7. package/dist/410.js +1 -1
  8. package/dist/410.js.map +1 -1
  9. package/dist/457.js +2 -0
  10. package/dist/457.js.LICENSE.txt +261 -0
  11. package/dist/457.js.map +1 -0
  12. package/dist/480.js +1 -0
  13. package/dist/781.js +1 -0
  14. package/dist/781.js.map +1 -0
  15. package/dist/907.js +1 -1
  16. package/dist/907.js.map +1 -1
  17. package/dist/953.css +1 -0
  18. package/dist/953.css.map +1 -0
  19. package/dist/953.js +1 -0
  20. package/dist/953.js.map +1 -0
  21. package/dist/99.js +1 -1
  22. package/dist/99.js.map +1 -0
  23. package/dist/ampath-esm-reports-app.js +1 -1
  24. package/dist/routes.json +1 -1
  25. package/package.json +3 -1
  26. package/src/common/linelist-table/linelist-table.component.tsx +1 -1
  27. package/src/common/report-filters/report-filters.component.tsx +25 -4
  28. package/src/common/report-filters/types.ts +13 -0
  29. package/src/common/report-page/download-sheet-pdf.ts +59 -0
  30. package/src/common/report-page/index.ts +1 -0
  31. package/src/dashboard/reports-dasboard.tsx +156 -69
  32. package/src/dashboard/reports-dashboard.module.scss +144 -59
  33. package/src/registers/moh-362/moh-362-lab-register.component.tsx +392 -0
  34. package/src/registers/moh-362/moh-362-linkage-register.component.tsx +120 -0
  35. package/src/registers/moh-362/moh-362-register.scss +222 -0
  36. package/src/registers/moh-362/moh-362.component.tsx +99 -0
  37. package/src/registers/moh-362/moh-362.scss +11 -0
  38. package/src/registers/moh-362/moh-362.types.ts +97 -0
  39. package/src/registers/register-catalog.ts +30 -0
  40. package/src/reports/moh-731/linelist/moh-731-indicators.ts +82 -0
  41. package/src/reports/moh-731/linelist/moh-731-linelist-sections.ts +51 -2
  42. package/src/reports/moh-731/moh-731.component.tsx +18 -3
  43. package/src/reports/moh-731/moh-731.scss +6 -0
  44. package/src/reports/moh-731/sections/hiv-and-tb-treatment.component.tsx +49 -52
  45. package/src/reports/moh-731/summary/moh-731-summary.config.ts +25 -16
  46. package/src/resources/moh-362.resource.ts +27 -0
  47. package/src/root.component.tsx +2 -0
  48. package/dist/876.css +0 -1
  49. package/dist/876.css.map +0 -1
  50. package/dist/876.js +0 -1
  51. package/dist/876.js.map +0 -1
@@ -1 +1 @@
1
- var _ampath_esm_reports_app;!function(){var e="undefined"!=typeof globalThis?globalThis:self;if(void 0===e._FEDERATION_RUNTIME_CORE||void 0===e._OPENMRS_FEDERATION_SDK||void 0===e._OPENMRS_FEDERATION_ERROR_CODES)throw new Error("@ampath/esm-reports-app cannot start: the OpenMRS app shell serving this page does not provide the Module Federation runtime. This app was built with newer OpenMRS tooling than the app shell, so either upgrade @openmrs/esm-app-shell, or rebuild this app with tooling matching the app shell.");var r=e._FEDERATION_RUNTIME_CORE_FROM;r&&r.version&&"2.8"!==String(r.version).split(".").slice(0,2).join(".")&&console.warn("@ampath/esm-reports-app was built against Module Federation 2.8.x but the app shell provides "+r.version+". Shared dependencies may not de-duplicate correctly.")}(),(()=>{"use strict";var e,r,t,n,a,o,i={2464(e,r,t){var n={};function a(e){e.S&&!e.federation.hasAttachShareScopeMap&&e.federation.instance&&e.federation.instance.shareScopeMap&&(e.S=e.federation.instance.shareScopeMap,e.federation.hasAttachShareScopeMap=!0)}t.r(n),t.d(n,{Module:()=>p.Module,ModuleFederation:()=>p.ModuleFederation,createInstance:()=>h,getInstance:()=>M,getRemoteEntry:()=>p.getRemoteEntry,getRemoteInfo:()=>p.getRemoteInfo,init:()=>m,loadRemote:()=>g,loadScript:()=>p.loadScript,loadScriptNode:()=>p.loadScriptNode,loadShare:()=>y,loadShareSync:()=>S,preloadRemote:()=>b,registerGlobalPlugins:()=>p.registerGlobalPlugins,registerPlugins:()=>E,registerRemotes:()=>v,registerShared:()=>R});const o=["script"];function i(e){const{webpackRequire:r,moduleToHandlerMapping:t}=e,{consumesLoadingData:n,initializeSharingData:a}=r,{sharedFallback:o,bundlerRuntime:i,libraryType:s}=r.federation;if(n&&!n._updated){const{moduleIdToConsumeDataMapping:a={},initialConsumes:c=[],chunkMapping:l={}}=n;if(Object.entries(a).forEach(([e,n])=>{t[e]||(t[e]={getter:o?i?.getSharedFallbackGetter({shareKey:n.shareKey,factory:n.fallback,webpackRequire:r,libraryType:s}):n.fallback,treeShakingGetter:o?n.fallback:void 0,shareInfo:{shareConfig:{requiredVersion:n.requiredVersion,strictVersion:n.strictVersion,singleton:n.singleton,eager:n.eager,layer:n.layer},scope:Array.isArray(n.shareScope)?n.shareScope:[n.shareScope||"default"],treeShaking:o?{get:n.fallback,mode:n.treeShakingMode}:void 0},shareKey:n.shareKey})}),"initialConsumes"in e){const{initialConsumes:r=[]}=e;c.forEach(e=>{r.includes(e)||r.push(e)})}if("chunkMapping"in e){const{chunkMapping:r={}}=e;Object.entries(l).forEach(([e,t])=>{r[e]||(r[e]=[]),t.forEach(t=>{r[e].includes(t)||r[e].push(t)})})}n._updated=1}if(a&&!a._updated){const{federation:e}=r;if(!e.instance||!a.scopeToSharingDataMapping)return;const t={};for(let[e,r]of Object.entries(a.scopeToSharingDataMapping))for(let n of r)if("object"==typeof n&&null!==n){const{name:r,version:a,factory:o,eager:i,singleton:s,requiredVersion:c,strictVersion:l}=n,p={requiredVersion:`^${a}`},u=function(e){return void 0!==e};u(s)&&(p.singleton=s),u(c)&&(p.requiredVersion=c),u(i)&&(p.eager=i),u(l)&&(p.strictVersion=l);const d={version:a,scope:[e],shareConfig:p,get:o};t[r]?t[r].push(d):t[r]=[d]}e.instance.registerShared(t),a._updated=1}}const s=self._OPENMRS_FEDERATION_SDK;function c(e,r){const t=e.federation.usedExports;if(t)return t[r]}const l="RUNTIME-012",p=self._FEDERATION_RUNTIME_CORE;function u(e,r){return p.CurrentGlobal.__FEDERATION__.__INSTANCES__.find(t=>!("@ampath/esm-reports-app:1.0.0-next.63"!==t.options.id&&(t.options.name!==e||t.options.version||r)&&(t.options.name!==e||!r||t.options.version!==r)))}const d=self._OPENMRS_FEDERATION_ERROR_CODES;function h(e){const r=new((0,p.getGlobalFederationConstructor)()||p.ModuleFederation)({id:`${e.name}@${e.version||Date.now()}`,...e});return(0,p.setGlobalFederationInstance)(r),r}let f=null;function m(e){const r=u(e.name,e.version),t={...e,id:e.id||""};return r?(r.initOptions(t),f||(f=r),r):(f=h(t),f)}function g(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.loadRemote.apply(f,e)}function y(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.loadShare.apply(f,e)}function S(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.loadShareSync.apply(f,e)}function b(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.preloadRemote.apply(f,e)}function v(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.registerRemotes.apply(f,e)}function E(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.registerPlugins.apply(f,e)}function M(e){return e?p.CurrentGlobal.__FEDERATION__.__INSTANCES__.find(e)||null:f}function R(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.registerShared.apply(f,e)}(0,p.setGlobalFederationConstructor)(p.ModuleFederation);const k={global:{...p.helpers.global,getGlobalFederationInstance:u},share:p.helpers.share,utils:p.helpers.utils},_={remotes:function(e){!function(e){const{webpackRequire:r,idToExternalAndNameMapping:t={},idToRemoteMap:n={},chunkMapping:a={}}=e,{remotesLoadingData:o}=r,i=r.federation?.bundlerRuntimeOptions?.remotes?.remoteInfos;if(!o||o._updated||!i)return;const{chunkMapping:s,moduleIdToRemoteDataMapping:c}=o;if(s&&c){for(let[e,r]of Object.entries(c))if(t[e]||(t[e]=[r.shareScope,r.name,r.externalModuleId]),!n[e]&&i[r.remoteName]){const t=i[r.remoteName];n[e]||=[],t.forEach(r=>{n[e].includes(r)||n[e].push(r)})}a&&Object.entries(s).forEach(([e,r])=>{a[e]||(a[e]=[]),r.forEach(r=>{a[e].includes(r)||a[e].push(r)})}),o._updated=1}}(e);const{chunkId:r,promises:t,webpackRequire:n,chunkMapping:i,idToExternalAndNameMapping:c,idToRemoteMap:l}=e;a(n),n.o(i,r)&&i[r].forEach(e=>{let r=n.R;r||(r=[]);const a=c[e],i=l[e]||[];if(r.indexOf(a)>=0)return;if(r.push(a),a.p)return t.push(a.p);const p=r=>{r||(r=new Error("Container missing")),"string"==typeof r.message&&(r.message+=`\nwhile loading "${a[1]}" from ${a[2]}`),n.m[e]=()=>{throw r},a.p=0},u=(e,r,n,o,i,s)=>{try{const c=e(r,n);if(!c||!c.then)return i(c,o,s);{const e=c.then(e=>i(e,o),p);if(!s)return e;t.push(a.p=e)}}catch(e){p(e)}};var d=(e,t,n)=>u(t.get,a[1],r,0,h,n),h=r=>{a.p=1,n.m[e]=e=>{e.exports=r()}};1===i.length&&o.includes(i[0].externalType)&&i[0].name?u(()=>{try{const e=(0,s.decodeName)(i[0].name,s.ENCODE_NAME_PREFIX)+a[1].slice(1),r=n.federation.instance,t=()=>n.federation.instance.loadRemote(e,{loadFactory:!1,from:"build"});if("version-first"===r.options.shareStrategy){const e=Array.isArray(a[0])?a[0]:[a[0]];return Promise.all(e.map(e=>r.sharedHandler.initializeSharing(e))).then(()=>t())}return t()}catch(e){p(e)}},a[2],0,0,h,1):u(n,a[2],0,0,(e,r,t)=>e?u(n.I,a[0],0,e,d,t):p(),1)})},consumes:function(e){i(e);const{chunkId:r,promises:t,installedModules:n,webpackRequire:o,chunkMapping:s,moduleToHandlerMapping:p}=e;a(o),o.o(s,r)&&s[r].forEach(e=>{if(o.o(n,e))return t.push(n[e]);const r=r=>{n[e]=0,o.m[e]=t=>{delete o.c[e];const n=r(),{shareInfo:a}=p[e];if(a?.shareConfig?.layer&&n&&"object"==typeof n)try{n.hasOwnProperty("layer")&&void 0!==n.layer||(n.layer=a.shareConfig.layer)}catch(e){}t.exports=n}},a=r=>{delete n[e],o.m[e]=t=>{throw delete o.c[e],r}};try{const i=o.federation.instance;if(!i)throw new Error("Federation instance not found!");const{shareKey:s,getter:u,shareInfo:d,treeShakingGetter:h}=p[e],f=c(o,s),m={...d};Array.isArray(m.scope)&&Array.isArray(m.scope[0])&&(m.scope=m.scope[0]),f&&(m.treeShaking={usedExports:f,useIn:[i.options.name]});const g=i.loadShare(s,{customShareInfo:m}).then(e=>{if(!1===e){if("function"!=typeof u)throw new Error(((e,r,t)=>{const n=[`${[r[e]]} #${e}`];return t&&n.push(`args: ${JSON.stringify(t)}`),n.push((e=>`View the docs to see how to solve: https://module-federation.io/guide/troubleshooting/${e.split("-")[0].toLowerCase()}#${e.toLowerCase()}`)(e)),n.join("\n")})(l,{[l]:'The getter for the shared module is not a function. This may be caused by setting "shared.import: false" without the host providing the corresponding lib.'},{shareKey:s}));return h?.()||u()}return e});g.then?t.push(n[e]=g.then(r).catch(a)):r(g)}catch(e){a(e)}})},I:function({shareScopeName:e,webpackRequire:r,initPromises:t,initTokens:n,initScope:i}){const s=Array.isArray(e)?e:[e];var c=[];return s.forEach(s=>{c.push(function(s){i||(i=[]);const c=r.federation.instance;var l=n[s];if(l||(l=n[s]={from:c.name}),i.indexOf(l)>=0)return;i.push(l);const p=t[s];if(p)return p;var u=t=>{var n=e=>{return r="Initialization of sharing external failed: "+e,"undefined"!=typeof console&&console.warn&&console.warn(r);var r};try{var a=r(t);if(!a)return;var o=t=>t&&t.init&&t.init(r.S[s],i,{shareScopeMap:r.S||{},shareScopeKeys:e});if(a.then)return d.push(a.then(o,n));var c=o(a);if(c&&"boolean"!=typeof c&&c.then)return d.push(c.catch(n))}catch(e){n(e)}};const d=c.initializeSharing(s,{strategy:c.options.shareStrategy,initScope:i,from:"build"});a(r);const h=r.federation.bundlerRuntimeOptions.remotes;return h&&Object.keys(h.idToRemoteMap).forEach(e=>{const r=h.idToRemoteMap[e],t=h.idToExternalAndNameMapping[e][2];if(r.length>1)u(t);else if(1===r.length){const e=r[0];o.includes(e.externalType)||u(t)}}),d.length?t[s]=Promise.all(d).then(()=>t[s]=!0):t[s]=!0}(s))}),Promise.all(c).then(()=>!0)},S:{},installInitialConsumes:function(e){i(e);const{moduleToHandlerMapping:r,webpackRequire:t,installedModules:n,initialConsumes:a,asyncLoad:o}=e,s=[];a.forEach(e=>{s.push([e,()=>function(e){const{moduleId:r,moduleToHandlerMapping:t,webpackRequire:n,asyncLoad:a}=e,o=n.federation.instance;if(!o)throw new Error("Federation instance not found!");const{shareKey:i,shareInfo:s}=t[r];try{const e=c(n,i),r={...s};return e&&(r.treeShaking={usedExports:e,useIn:[o.options.name]}),a?o.loadShare(i,{customShareInfo:r}):o.loadShareSync(i,{customShareInfo:r})}catch(e){throw console.error('loadShareSync failed! The function should not be called unless you set "eager:true". If you do not set it, and encounter this issue, you can check whether an async boundary is implemented.'),console.error("The original error message is as follows: "),e}}({moduleId:e,moduleToHandlerMapping:r,webpackRequire:t,asyncLoad:o})])});const l=(e,a)=>{t.m[e]=o=>{n[e]=0,delete t.c[e];const i=a();if("function"!=typeof i)throw new Error(`Shared module is not available for eager consumption: ${e}`);const s=i(),{shareInfo:c}=r[e];if(c?.shareConfig?.layer&&s&&"object"==typeof s)try{s.hasOwnProperty("layer")&&void 0!==s.layer||(s.layer=c.shareConfig.layer)}catch(e){}o.exports=s}};if(o)return Promise.all(s.map(async([e,r])=>{const t=await r();l(e,()=>t)}));s.forEach(([e,r])=>{l(e,r)})},initContainerEntry:function(e){const{webpackRequire:r,shareScope:t,initScope:n,shareScopeKey:a,remoteEntryInitOptions:o}=e;if(!r.S)return;if(!r.federation||!r.federation.instance||!r.federation.initOptions)return;const i=r.federation.instance;i.initOptions({name:r.federation.initOptions.name,remotes:[],...o});const s=o?.shareScopeKeys,c=o?.shareScopeMap;if(a&&"string"!=typeof a)a.forEach(e=>{if(!s||!c)return void i.initShareScopeMap(e,t,{hostShareScopeMap:o?.shareScopeMap||{}});c[e]||(c[e]={});const r=c[e];i.initShareScopeMap(e,r,{hostShareScopeMap:o?.shareScopeMap||{}})});else{const e=a||"default";Array.isArray(s)?s.forEach(e=>{c[e]||(c[e]={});const r=c[e];i.initShareScopeMap(e,r,{hostShareScopeMap:o?.shareScopeMap||{}})}):i.initShareScopeMap(e,t,{hostShareScopeMap:o?.shareScopeMap||{}})}return r.federation.attachShareScopeMap&&r.federation.attachShareScopeMap(r),Array.isArray(a)?Boolean(r.federation.initOptions.shared)?r.I(a,n):Promise.all(a.map(e=>r.I(e,n))).then(()=>!0):r.I(a||"default",n)},init:function({webpackRequire:e}){const{initOptions:r,runtime:n,sharedFallback:a,bundlerRuntime:o,libraryType:i}=e.federation;if(!r)throw new Error("initOptions is required!");{const n=function(){return{name:"tree-shake-plugin",beforeInit(r){const{userOptions:n,origin:s,options:c}=r,l=n.version||c.version;if(!a)return r;const u=n.shared||{},d=[];Object.keys(u).forEach(r=>{(Array.isArray(u[r])?u[r]:[u[r]]).forEach(t=>{d.push([r,t]),"get"in t&&(t.treeShaking||={},t.treeShaking.get=t.get,t.get=o.getSharedFallbackGetter({shareKey:r,factory:t.get,webpackRequire:e,libraryType:i,version:t.version}))})});const h=k.global.getGlobalSnapshotInfoByModuleInfo({name:s.name,version:l});return h&&"shared"in h?(Object.keys(c.shared||{}).forEach(e=>{c.shared[e].forEach(r=>{d.push([e,r])})}),d.forEach(([e,r])=>{((e,r)=>{const n=h.shared.find(r=>r.sharedName===e);if(!n)return;const{treeShaking:a}=r;if(!a)return;const{secondarySharedTreeShakingName:o,secondarySharedTreeShakingEntry:c,treeShakingStatus:l}=n;a.status!==l&&(a.status=l,c&&i&&o&&(a.get=async()=>{const e=await(0,p.getRemoteEntry)({origin:s,remoteInfo:{name:o,entry:c,type:i,entryGlobalName:o,shareScope:"default"}});return await e.init(s,t.federation.bundlerRuntime),e.get()}))})(e,r)}),r):r}}};r.plugins||=[],r.plugins.push(n())}return n.init(r)},getSharedFallbackGetter:({shareKey:e,factory:r,version:t,webpackRequire:n,libraryType:a="global"})=>{const{runtime:o,instance:i,bundlerRuntime:s,sharedFallback:c}=n.federation;if(!c)return r;const l=c[e];if(!l)return r;const p=t?l.find(e=>e[1]===t):l[0];if(!p)throw new Error(`No fallback item found for shareKey: ${e} and version: ${t}`);return()=>o.getRemoteEntry({origin:n.federation.instance,remoteInfo:{name:p[2],entry:`${n.p}${p[0]}`,type:a,entryGlobalName:p[2],shareScope:"default"}}).then(r=>{if(!r)throw new Error(`Failed to load fallback entry for shareKey: ${e} and version: ${t}`);return r.init(n.federation.instance,s).then(()=>r.get())})}},w={runtime:n,instance:void 0,initOptions:void 0,bundlerRuntime:_,attachShareScopeMap:a,bundlerRuntimeOptions:{}};if(!t.federation.runtime||!t.federation.bundlerRuntime){var I=t.federation;for(var T in t.federation={},w)t.federation[T]=w[T];for(var T in I)t.federation[T]=I[T]}t.federation.instance||(t.federation.instance=t.federation.bundlerRuntime.init({webpackRequire:t}),t.federation.attachShareScopeMap&&t.federation.attachShareScopeMap(t),t.federation.installInitialConsumes&&t.federation.installInitialConsumes())},9421(e,r,t){var n={"./start":()=>Promise.all([t.e(31),t.e(435),t.e(410)]).then(()=>()=>t(5410))},a=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then(()=>{throw new Error('Module "'+e+'" does not exist in container.')}),t.R=void 0,r),o=(e,r,n)=>t.federation.bundlerRuntime.initContainerEntry({webpackRequire:t,shareScope:e,initScope:r,remoteEntryInitOptions:n,shareScopeKey:"default"});t.d(r,{get:()=>a,init:()=>o})}},s={};function c(e){var r=s[e];if(void 0!==r)return r.exports;var t=s[e]={exports:{}},n={id:e,module:t,factory:i[e],require:c};return c.i.forEach(function(e){e(n)}),t=n.module,n.factory.call(t.exports,t,t.exports,n.require),t.exports}c.m=i,c.c=s,c.i=[],c.x=e=>{},c.federation||(c.federation={initOptions:{name:"@ampath/esm-reports-app",remotes:[],shareStrategy:"version-first"},chunkMatcher:function(e){return!/^(31|435|680|987)$/.test(e)},rootOutputDir:"",bundlerRuntimeOptions:{remotes:{remoteInfos:{},webpackRequire:c,idToRemoteMap:{},chunkMapping:{},idToExternalAndNameMapping:{}}}},c.consumesLoadingData={},c.remotesLoadingData={}),c.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return c.d(r,{a:r}),r},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,c.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 a=Object.create(null);c.r(a);var o={};e=e||[null,r({}),r([]),r(r)];for(var i=2&n&&t;("object"==typeof i||"function"==typeof i)&&!~e.indexOf(i);i=r(i))Object.getOwnPropertyNames(i).forEach(e=>o[e]=()=>t[e]);return o.default=()=>t,c.d(a,o),a},c.d=(e,r)=>{for(var t in r)c.o(r,t)&&!c.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},c.f={},c.e=e=>Promise.all(Object.keys(c.f).reduce((r,t)=>(c.f[t](e,r),r),[])),c.u=e=>e+".js",c.miniCssF=e=>e+".css",c.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t={},n="@ampath/esm-reports-app:",c.l=(e,r,a,o)=>{if(t[e])t[e].push(r);else{var i,s;if(void 0!==a)for(var l=document.getElementsByTagName("script"),p=0;p<l.length;p++){var u=l[p];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==n+a){i=u;break}}i||(s=!0,(i=document.createElement("script")).charset="utf-8",c.nc&&i.setAttribute("nonce",c.nc),i.setAttribute("data-webpack",n+a),i.src=e),t[e]=[r];var d=(r,n)=>{i.onerror=i.onload=null,clearTimeout(h);var a=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),a&&a.forEach(e=>e(n)),r)return r(n)},h=setTimeout(d.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),s&&document.head.appendChild(i)}},c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{c.S={};var e={},r={};c.I=(t,n)=>{n||(n=[]);var a=r[t];if(a||(a=r[t]={}),!(n.indexOf(a)>=0)){if(n.push(a),e[t])return e[t];c.o(c.S,t)||(c.S[t]={});var o=c.S[t],i="@ampath/esm-reports-app",s=(e,r,t,n)=>{var a=o[e]=o[e]||{},s=a[r];(!s||!s.loaded&&(!n!=!s.eager?n:i>s.from))&&(a[r]={get:t,from:i,eager:!!n})},l=[];return"default"===t&&(s("@openmrs/esm-framework","11.0.1-pre.5776",()=>Promise.all([c.e(961),c.e(907),c.e(478),c.e(295),c.e(31),c.e(680),c.e(435),c.e(987)]).then(()=>()=>c(9295))),s("dayjs","1.11.20",()=>c.e(353).then(()=>()=>c(4353))),s("react-i18next","16.6.6",()=>Promise.all([c.e(478),c.e(311),c.e(31)]).then(()=>()=>c(3311))),s("react-router-dom","6.30.3",()=>Promise.all([c.e(961),c.e(282),c.e(31)]).then(()=>()=>c(282))),s("react","18.3.1",()=>c.e(540).then(()=>()=>c(6540)))),e[t]=l.length?Promise.all(l).then(()=>e[t]=1):1}}})(),(()=>{c.federation.initOptions.shared={"@openmrs/esm-framework":[{version:"11.0.1-pre.5776",get:()=>Promise.all([c.e(961),c.e(907),c.e(478),c.e(295),c.e(31),c.e(680),c.e(435),c.e(987)]).then(()=>()=>c(9295)),scope:["default"],shareConfig:{eager:!1,requiredVersion:"*",strictVersion:!1,singleton:!0,layer:null}}],dayjs:[{version:"1.11.20",get:()=>c.e(353).then(()=>()=>c(4353)),scope:["default"],shareConfig:{eager:!1,requiredVersion:"1.x",strictVersion:!1,singleton:!0,layer:null}}],"react-i18next":[{version:"16.6.6",get:()=>Promise.all([c.e(478),c.e(311),c.e(31)]).then(()=>()=>c(3311)),scope:["default"],shareConfig:{eager:!1,requiredVersion:"16.x",strictVersion:!1,singleton:!0,layer:null}}],"react-router-dom":[{version:"6.30.3",get:()=>Promise.all([c.e(961),c.e(282),c.e(31)]).then(()=>()=>c(282)),scope:["default"],shareConfig:{eager:!1,requiredVersion:"6.x",strictVersion:!1,singleton:!0,layer:null}}],react:[{version:"18.3.1",get:()=>c.e(540).then(()=>()=>c(6540)),scope:["default"],shareConfig:{eager:!1,requiredVersion:"18.x",strictVersion:!1,singleton:!0,layer:null}}]},c.S={};var e={},r={};c.I=(t,n)=>c.federation.bundlerRuntime.I({shareScopeName:t,webpackRequire:c,initPromises:e,initTokens:r,initScope:n})})(),(()=>{var e;globalThis.importScripts&&(e=globalThis.location+"");var r=globalThis.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(/\/[^\/]+$/,"/"),c.p=e})(),(()=>{var e={};c.consumesLoadingData.moduleIdToConsumeDataMapping={6031:{fallback:()=>c.e(540).then(()=>()=>c(6540)),shareScope:["default"],singleton:!0,requiredVersion:"18.x",strictVersion:!1,eager:!1,layer:void 0,shareKey:"react"},6435:{fallback:()=>Promise.all([c.e(961),c.e(282)]).then(()=>()=>c(282)),shareScope:["default"],singleton:!0,requiredVersion:"6.x",strictVersion:!1,eager:!1,layer:void 0,shareKey:"react-router-dom"},7693:{fallback:()=>Promise.all([c.e(961),c.e(907),c.e(478),c.e(295),c.e(680),c.e(987)]).then(()=>()=>c(9295)),shareScope:["default"],singleton:!0,requiredVersion:"*",strictVersion:!1,eager:!1,layer:void 0,shareKey:"@openmrs/esm-framework"},7680:{fallback:()=>c.e(353).then(()=>()=>c(4353)),shareScope:["default"],singleton:!0,requiredVersion:"1.x",strictVersion:!1,eager:!1,layer:void 0,shareKey:"dayjs"},3987:{fallback:()=>c.e(311).then(()=>()=>c(3311)),shareScope:["default"],singleton:!0,requiredVersion:"16.x",strictVersion:!1,eager:!1,layer:void 0,shareKey:"react-i18next"}};var r={};c.consumesLoadingData.chunkMapping={31:[6031],410:[7693],435:[6435],680:[7680],987:[3987]},c.f.consumes=(t,n)=>{c.federation.bundlerRuntime.consumes({chunkMapping:c.consumesLoadingData.chunkMapping,installedModules:e,chunkId:t,moduleToHandlerMapping:r,promises:n,webpackRequire:c})}})(),(()=>{if("undefined"!=typeof document){var e={462:0};c.f.miniCss=(r,t)=>{e[r]?t.push(e[r]):0!==e[r]&&{295:1,876:1}[r]&&t.push(e[r]=(e=>new Promise((r,t)=>{var n=c.miniCssF(e),a=c.p+n;if(((e,r)=>{for(var t=document.getElementsByTagName("link"),n=0;n<t.length;n++){var a=(i=t[n]).getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(a===e||a===r))return i}var o=document.getElementsByTagName("style");for(n=0;n<o.length;n++){var i;if((a=(i=o[n]).getAttribute("data-href"))===e||a===r)return i}})(n,a))return r();((e,r,t,n,a)=>{var o=document.createElement("link");o.rel="stylesheet",o.type="text/css",c.nc&&(o.nonce=c.nc),o.onerror=o.onload=t=>{if(o.onerror=o.onload=null,"load"===t.type)n();else{var i=t&&t.type,s=t&&t.target&&t.target.href||r,c=new Error("Loading CSS chunk "+e+" failed.\n("+i+": "+s+")");c.name="ChunkLoadError",c.code="CSS_CHUNK_LOAD_FAILED",c.type=i,c.request=s,o.parentNode&&o.parentNode.removeChild(o),a(c)}},o.href=r,document.head.appendChild(o)})(e,a,0,r,t)}))(r).then(()=>{e[r]=0},t=>{throw delete e[r],t}))}}})(),a=c.x,o=!1,c.x=()=>{if(o||(o=!0,c(2464)),"function"==typeof a)return a();console.warn("[Module Federation] prevStartup is not a function, skipping startup execution")},(()=>{var e={462:0};c.f.j=(r,t)=>{var n=c.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else if(/^(31|435|680|987)$/.test(r))e[r]=0;else{var a=new Promise((t,a)=>n=e[r]=[t,a]);t.push(n[2]=a);var o=c.p+c.u(r),i=new Error;c.l(o,t=>{if(c.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+a+": "+o+")",i.name="ChunkLoadError",i.type=a,i.request=o,n[1](i)}},"chunk-"+r,r)}};var r=(r,t)=>{var n,a,[o,i,s]=t,l=0;if(o.some(r=>0!==e[r])){for(n in i)c.o(i,n)&&(c.m[n]=i[n]);s&&s(c)}for(r&&r(t);l<o.length;l++)a=o[l],c.o(e,a)&&e[a]&&e[a][0](),e[a]=0},t=self.webpackChunk_ampath_esm_reports_app=self.webpackChunk_ampath_esm_reports_app||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),c.x();var l=c(9421);_ampath_esm_reports_app=l})();
1
+ var _ampath_esm_reports_app;!function(){var e="undefined"!=typeof globalThis?globalThis:self;if(void 0===e._FEDERATION_RUNTIME_CORE||void 0===e._OPENMRS_FEDERATION_SDK||void 0===e._OPENMRS_FEDERATION_ERROR_CODES)throw new Error("@ampath/esm-reports-app cannot start: the OpenMRS app shell serving this page does not provide the Module Federation runtime. This app was built with newer OpenMRS tooling than the app shell, so either upgrade @openmrs/esm-app-shell, or rebuild this app with tooling matching the app shell.");var r=e._FEDERATION_RUNTIME_CORE_FROM;r&&r.version&&"2.8"!==String(r.version).split(".").slice(0,2).join(".")&&console.warn("@ampath/esm-reports-app was built against Module Federation 2.8.x but the app shell provides "+r.version+". Shared dependencies may not de-duplicate correctly.")}(),(()=>{"use strict";var e,r,t,n,a,o,i={2464(e,r,t){var n={};function a(e){e.S&&!e.federation.hasAttachShareScopeMap&&e.federation.instance&&e.federation.instance.shareScopeMap&&(e.S=e.federation.instance.shareScopeMap,e.federation.hasAttachShareScopeMap=!0)}t.r(n),t.d(n,{Module:()=>p.Module,ModuleFederation:()=>p.ModuleFederation,createInstance:()=>h,getInstance:()=>M,getRemoteEntry:()=>p.getRemoteEntry,getRemoteInfo:()=>p.getRemoteInfo,init:()=>m,loadRemote:()=>g,loadScript:()=>p.loadScript,loadScriptNode:()=>p.loadScriptNode,loadShare:()=>y,loadShareSync:()=>S,preloadRemote:()=>b,registerGlobalPlugins:()=>p.registerGlobalPlugins,registerPlugins:()=>E,registerRemotes:()=>v,registerShared:()=>R});const o=["script"];function i(e){const{webpackRequire:r,moduleToHandlerMapping:t}=e,{consumesLoadingData:n,initializeSharingData:a}=r,{sharedFallback:o,bundlerRuntime:i,libraryType:s}=r.federation;if(n&&!n._updated){const{moduleIdToConsumeDataMapping:a={},initialConsumes:c=[],chunkMapping:l={}}=n;if(Object.entries(a).forEach(([e,n])=>{t[e]||(t[e]={getter:o?i?.getSharedFallbackGetter({shareKey:n.shareKey,factory:n.fallback,webpackRequire:r,libraryType:s}):n.fallback,treeShakingGetter:o?n.fallback:void 0,shareInfo:{shareConfig:{requiredVersion:n.requiredVersion,strictVersion:n.strictVersion,singleton:n.singleton,eager:n.eager,layer:n.layer},scope:Array.isArray(n.shareScope)?n.shareScope:[n.shareScope||"default"],treeShaking:o?{get:n.fallback,mode:n.treeShakingMode}:void 0},shareKey:n.shareKey})}),"initialConsumes"in e){const{initialConsumes:r=[]}=e;c.forEach(e=>{r.includes(e)||r.push(e)})}if("chunkMapping"in e){const{chunkMapping:r={}}=e;Object.entries(l).forEach(([e,t])=>{r[e]||(r[e]=[]),t.forEach(t=>{r[e].includes(t)||r[e].push(t)})})}n._updated=1}if(a&&!a._updated){const{federation:e}=r;if(!e.instance||!a.scopeToSharingDataMapping)return;const t={};for(let[e,r]of Object.entries(a.scopeToSharingDataMapping))for(let n of r)if("object"==typeof n&&null!==n){const{name:r,version:a,factory:o,eager:i,singleton:s,requiredVersion:c,strictVersion:l}=n,p={requiredVersion:`^${a}`},u=function(e){return void 0!==e};u(s)&&(p.singleton=s),u(c)&&(p.requiredVersion=c),u(i)&&(p.eager=i),u(l)&&(p.strictVersion=l);const d={version:a,scope:[e],shareConfig:p,get:o};t[r]?t[r].push(d):t[r]=[d]}e.instance.registerShared(t),a._updated=1}}const s=self._OPENMRS_FEDERATION_SDK;function c(e,r){const t=e.federation.usedExports;if(t)return t[r]}const l="RUNTIME-012",p=self._FEDERATION_RUNTIME_CORE;function u(e,r){return p.CurrentGlobal.__FEDERATION__.__INSTANCES__.find(t=>!("@ampath/esm-reports-app:1.0.0-next.64"!==t.options.id&&(t.options.name!==e||t.options.version||r)&&(t.options.name!==e||!r||t.options.version!==r)))}const d=self._OPENMRS_FEDERATION_ERROR_CODES;function h(e){const r=new((0,p.getGlobalFederationConstructor)()||p.ModuleFederation)({id:`${e.name}@${e.version||Date.now()}`,...e});return(0,p.setGlobalFederationInstance)(r),r}let f=null;function m(e){const r=u(e.name,e.version),t={...e,id:e.id||""};return r?(r.initOptions(t),f||(f=r),r):(f=h(t),f)}function g(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.loadRemote.apply(f,e)}function y(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.loadShare.apply(f,e)}function S(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.loadShareSync.apply(f,e)}function b(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.preloadRemote.apply(f,e)}function v(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.registerRemotes.apply(f,e)}function E(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.registerPlugins.apply(f,e)}function M(e){return e?p.CurrentGlobal.__FEDERATION__.__INSTANCES__.find(e)||null:f}function R(...e){return(0,p.assert)(f,d.RUNTIME_009,d.runtimeDescMap),f.registerShared.apply(f,e)}(0,p.setGlobalFederationConstructor)(p.ModuleFederation);const k={global:{...p.helpers.global,getGlobalFederationInstance:u},share:p.helpers.share,utils:p.helpers.utils},_={remotes:function(e){!function(e){const{webpackRequire:r,idToExternalAndNameMapping:t={},idToRemoteMap:n={},chunkMapping:a={}}=e,{remotesLoadingData:o}=r,i=r.federation?.bundlerRuntimeOptions?.remotes?.remoteInfos;if(!o||o._updated||!i)return;const{chunkMapping:s,moduleIdToRemoteDataMapping:c}=o;if(s&&c){for(let[e,r]of Object.entries(c))if(t[e]||(t[e]=[r.shareScope,r.name,r.externalModuleId]),!n[e]&&i[r.remoteName]){const t=i[r.remoteName];n[e]||=[],t.forEach(r=>{n[e].includes(r)||n[e].push(r)})}a&&Object.entries(s).forEach(([e,r])=>{a[e]||(a[e]=[]),r.forEach(r=>{a[e].includes(r)||a[e].push(r)})}),o._updated=1}}(e);const{chunkId:r,promises:t,webpackRequire:n,chunkMapping:i,idToExternalAndNameMapping:c,idToRemoteMap:l}=e;a(n),n.o(i,r)&&i[r].forEach(e=>{let r=n.R;r||(r=[]);const a=c[e],i=l[e]||[];if(r.indexOf(a)>=0)return;if(r.push(a),a.p)return t.push(a.p);const p=r=>{r||(r=new Error("Container missing")),"string"==typeof r.message&&(r.message+=`\nwhile loading "${a[1]}" from ${a[2]}`),n.m[e]=()=>{throw r},a.p=0},u=(e,r,n,o,i,s)=>{try{const c=e(r,n);if(!c||!c.then)return i(c,o,s);{const e=c.then(e=>i(e,o),p);if(!s)return e;t.push(a.p=e)}}catch(e){p(e)}};var d=(e,t,n)=>u(t.get,a[1],r,0,h,n),h=r=>{a.p=1,n.m[e]=e=>{e.exports=r()}};1===i.length&&o.includes(i[0].externalType)&&i[0].name?u(()=>{try{const e=(0,s.decodeName)(i[0].name,s.ENCODE_NAME_PREFIX)+a[1].slice(1),r=n.federation.instance,t=()=>n.federation.instance.loadRemote(e,{loadFactory:!1,from:"build"});if("version-first"===r.options.shareStrategy){const e=Array.isArray(a[0])?a[0]:[a[0]];return Promise.all(e.map(e=>r.sharedHandler.initializeSharing(e))).then(()=>t())}return t()}catch(e){p(e)}},a[2],0,0,h,1):u(n,a[2],0,0,(e,r,t)=>e?u(n.I,a[0],0,e,d,t):p(),1)})},consumes:function(e){i(e);const{chunkId:r,promises:t,installedModules:n,webpackRequire:o,chunkMapping:s,moduleToHandlerMapping:p}=e;a(o),o.o(s,r)&&s[r].forEach(e=>{if(o.o(n,e))return t.push(n[e]);const r=r=>{n[e]=0,o.m[e]=t=>{delete o.c[e];const n=r(),{shareInfo:a}=p[e];if(a?.shareConfig?.layer&&n&&"object"==typeof n)try{n.hasOwnProperty("layer")&&void 0!==n.layer||(n.layer=a.shareConfig.layer)}catch(e){}t.exports=n}},a=r=>{delete n[e],o.m[e]=t=>{throw delete o.c[e],r}};try{const i=o.federation.instance;if(!i)throw new Error("Federation instance not found!");const{shareKey:s,getter:u,shareInfo:d,treeShakingGetter:h}=p[e],f=c(o,s),m={...d};Array.isArray(m.scope)&&Array.isArray(m.scope[0])&&(m.scope=m.scope[0]),f&&(m.treeShaking={usedExports:f,useIn:[i.options.name]});const g=i.loadShare(s,{customShareInfo:m}).then(e=>{if(!1===e){if("function"!=typeof u)throw new Error(((e,r,t)=>{const n=[`${[r[e]]} #${e}`];return t&&n.push(`args: ${JSON.stringify(t)}`),n.push((e=>`View the docs to see how to solve: https://module-federation.io/guide/troubleshooting/${e.split("-")[0].toLowerCase()}#${e.toLowerCase()}`)(e)),n.join("\n")})(l,{[l]:'The getter for the shared module is not a function. This may be caused by setting "shared.import: false" without the host providing the corresponding lib.'},{shareKey:s}));return h?.()||u()}return e});g.then?t.push(n[e]=g.then(r).catch(a)):r(g)}catch(e){a(e)}})},I:function({shareScopeName:e,webpackRequire:r,initPromises:t,initTokens:n,initScope:i}){const s=Array.isArray(e)?e:[e];var c=[];return s.forEach(s=>{c.push(function(s){i||(i=[]);const c=r.federation.instance;var l=n[s];if(l||(l=n[s]={from:c.name}),i.indexOf(l)>=0)return;i.push(l);const p=t[s];if(p)return p;var u=t=>{var n=e=>{return r="Initialization of sharing external failed: "+e,"undefined"!=typeof console&&console.warn&&console.warn(r);var r};try{var a=r(t);if(!a)return;var o=t=>t&&t.init&&t.init(r.S[s],i,{shareScopeMap:r.S||{},shareScopeKeys:e});if(a.then)return d.push(a.then(o,n));var c=o(a);if(c&&"boolean"!=typeof c&&c.then)return d.push(c.catch(n))}catch(e){n(e)}};const d=c.initializeSharing(s,{strategy:c.options.shareStrategy,initScope:i,from:"build"});a(r);const h=r.federation.bundlerRuntimeOptions.remotes;return h&&Object.keys(h.idToRemoteMap).forEach(e=>{const r=h.idToRemoteMap[e],t=h.idToExternalAndNameMapping[e][2];if(r.length>1)u(t);else if(1===r.length){const e=r[0];o.includes(e.externalType)||u(t)}}),d.length?t[s]=Promise.all(d).then(()=>t[s]=!0):t[s]=!0}(s))}),Promise.all(c).then(()=>!0)},S:{},installInitialConsumes:function(e){i(e);const{moduleToHandlerMapping:r,webpackRequire:t,installedModules:n,initialConsumes:a,asyncLoad:o}=e,s=[];a.forEach(e=>{s.push([e,()=>function(e){const{moduleId:r,moduleToHandlerMapping:t,webpackRequire:n,asyncLoad:a}=e,o=n.federation.instance;if(!o)throw new Error("Federation instance not found!");const{shareKey:i,shareInfo:s}=t[r];try{const e=c(n,i),r={...s};return e&&(r.treeShaking={usedExports:e,useIn:[o.options.name]}),a?o.loadShare(i,{customShareInfo:r}):o.loadShareSync(i,{customShareInfo:r})}catch(e){throw console.error('loadShareSync failed! The function should not be called unless you set "eager:true". If you do not set it, and encounter this issue, you can check whether an async boundary is implemented.'),console.error("The original error message is as follows: "),e}}({moduleId:e,moduleToHandlerMapping:r,webpackRequire:t,asyncLoad:o})])});const l=(e,a)=>{t.m[e]=o=>{n[e]=0,delete t.c[e];const i=a();if("function"!=typeof i)throw new Error(`Shared module is not available for eager consumption: ${e}`);const s=i(),{shareInfo:c}=r[e];if(c?.shareConfig?.layer&&s&&"object"==typeof s)try{s.hasOwnProperty("layer")&&void 0!==s.layer||(s.layer=c.shareConfig.layer)}catch(e){}o.exports=s}};if(o)return Promise.all(s.map(async([e,r])=>{const t=await r();l(e,()=>t)}));s.forEach(([e,r])=>{l(e,r)})},initContainerEntry:function(e){const{webpackRequire:r,shareScope:t,initScope:n,shareScopeKey:a,remoteEntryInitOptions:o}=e;if(!r.S)return;if(!r.federation||!r.federation.instance||!r.federation.initOptions)return;const i=r.federation.instance;i.initOptions({name:r.federation.initOptions.name,remotes:[],...o});const s=o?.shareScopeKeys,c=o?.shareScopeMap;if(a&&"string"!=typeof a)a.forEach(e=>{if(!s||!c)return void i.initShareScopeMap(e,t,{hostShareScopeMap:o?.shareScopeMap||{}});c[e]||(c[e]={});const r=c[e];i.initShareScopeMap(e,r,{hostShareScopeMap:o?.shareScopeMap||{}})});else{const e=a||"default";Array.isArray(s)?s.forEach(e=>{c[e]||(c[e]={});const r=c[e];i.initShareScopeMap(e,r,{hostShareScopeMap:o?.shareScopeMap||{}})}):i.initShareScopeMap(e,t,{hostShareScopeMap:o?.shareScopeMap||{}})}return r.federation.attachShareScopeMap&&r.federation.attachShareScopeMap(r),Array.isArray(a)?Boolean(r.federation.initOptions.shared)?r.I(a,n):Promise.all(a.map(e=>r.I(e,n))).then(()=>!0):r.I(a||"default",n)},init:function({webpackRequire:e}){const{initOptions:r,runtime:n,sharedFallback:a,bundlerRuntime:o,libraryType:i}=e.federation;if(!r)throw new Error("initOptions is required!");{const n=function(){return{name:"tree-shake-plugin",beforeInit(r){const{userOptions:n,origin:s,options:c}=r,l=n.version||c.version;if(!a)return r;const u=n.shared||{},d=[];Object.keys(u).forEach(r=>{(Array.isArray(u[r])?u[r]:[u[r]]).forEach(t=>{d.push([r,t]),"get"in t&&(t.treeShaking||={},t.treeShaking.get=t.get,t.get=o.getSharedFallbackGetter({shareKey:r,factory:t.get,webpackRequire:e,libraryType:i,version:t.version}))})});const h=k.global.getGlobalSnapshotInfoByModuleInfo({name:s.name,version:l});return h&&"shared"in h?(Object.keys(c.shared||{}).forEach(e=>{c.shared[e].forEach(r=>{d.push([e,r])})}),d.forEach(([e,r])=>{((e,r)=>{const n=h.shared.find(r=>r.sharedName===e);if(!n)return;const{treeShaking:a}=r;if(!a)return;const{secondarySharedTreeShakingName:o,secondarySharedTreeShakingEntry:c,treeShakingStatus:l}=n;a.status!==l&&(a.status=l,c&&i&&o&&(a.get=async()=>{const e=await(0,p.getRemoteEntry)({origin:s,remoteInfo:{name:o,entry:c,type:i,entryGlobalName:o,shareScope:"default"}});return await e.init(s,t.federation.bundlerRuntime),e.get()}))})(e,r)}),r):r}}};r.plugins||=[],r.plugins.push(n())}return n.init(r)},getSharedFallbackGetter:({shareKey:e,factory:r,version:t,webpackRequire:n,libraryType:a="global"})=>{const{runtime:o,instance:i,bundlerRuntime:s,sharedFallback:c}=n.federation;if(!c)return r;const l=c[e];if(!l)return r;const p=t?l.find(e=>e[1]===t):l[0];if(!p)throw new Error(`No fallback item found for shareKey: ${e} and version: ${t}`);return()=>o.getRemoteEntry({origin:n.federation.instance,remoteInfo:{name:p[2],entry:`${n.p}${p[0]}`,type:a,entryGlobalName:p[2],shareScope:"default"}}).then(r=>{if(!r)throw new Error(`Failed to load fallback entry for shareKey: ${e} and version: ${t}`);return r.init(n.federation.instance,s).then(()=>r.get())})}},w={runtime:n,instance:void 0,initOptions:void 0,bundlerRuntime:_,attachShareScopeMap:a,bundlerRuntimeOptions:{}};if(!t.federation.runtime||!t.federation.bundlerRuntime){var I=t.federation;for(var T in t.federation={},w)t.federation[T]=w[T];for(var T in I)t.federation[T]=I[T]}t.federation.instance||(t.federation.instance=t.federation.bundlerRuntime.init({webpackRequire:t}),t.federation.attachShareScopeMap&&t.federation.attachShareScopeMap(t),t.federation.installInitialConsumes&&t.federation.installInitialConsumes())},9421(e,r,t){var n={"./start":()=>Promise.all([t.e(31),t.e(435),t.e(410)]).then(()=>()=>t(5410))},a=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then(()=>{throw new Error('Module "'+e+'" does not exist in container.')}),t.R=void 0,r),o=(e,r,n)=>t.federation.bundlerRuntime.initContainerEntry({webpackRequire:t,shareScope:e,initScope:r,remoteEntryInitOptions:n,shareScopeKey:"default"});t.d(r,{get:()=>a,init:()=>o})}},s={};function c(e){var r=s[e];if(void 0!==r)return r.exports;var t=s[e]={exports:{}},n={id:e,module:t,factory:i[e],require:c};return c.i.forEach(function(e){e(n)}),t=n.module,n.factory.call(t.exports,t,t.exports,n.require),t.exports}c.m=i,c.c=s,c.i=[],c.x=e=>{},c.federation||(c.federation={initOptions:{name:"@ampath/esm-reports-app",remotes:[],shareStrategy:"version-first"},chunkMatcher:function(e){return!/^(31|435|680|987)$/.test(e)},rootOutputDir:"",bundlerRuntimeOptions:{remotes:{remoteInfos:{},webpackRequire:c,idToRemoteMap:{},chunkMapping:{},idToExternalAndNameMapping:{}}}},c.consumesLoadingData={},c.remotesLoadingData={}),c.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return c.d(r,{a:r}),r},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,c.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 a=Object.create(null);c.r(a);var o={};e=e||[null,r({}),r([]),r(r)];for(var i=2&n&&t;("object"==typeof i||"function"==typeof i)&&!~e.indexOf(i);i=r(i))Object.getOwnPropertyNames(i).forEach(e=>o[e]=()=>t[e]);return o.default=()=>t,c.d(a,o),a},c.d=(e,r)=>{for(var t in r)c.o(r,t)&&!c.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},c.f={},c.e=e=>Promise.all(Object.keys(c.f).reduce((r,t)=>(c.f[t](e,r),r),[])),c.u=e=>e+".js",c.miniCssF=e=>e+".css",c.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t={},n="@ampath/esm-reports-app:",c.l=(e,r,a,o)=>{if(t[e])t[e].push(r);else{var i,s;if(void 0!==a)for(var l=document.getElementsByTagName("script"),p=0;p<l.length;p++){var u=l[p];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==n+a){i=u;break}}i||(s=!0,(i=document.createElement("script")).charset="utf-8",c.nc&&i.setAttribute("nonce",c.nc),i.setAttribute("data-webpack",n+a),i.src=e),t[e]=[r];var d=(r,n)=>{i.onerror=i.onload=null,clearTimeout(h);var a=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),a&&a.forEach(e=>e(n)),r)return r(n)},h=setTimeout(d.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),s&&document.head.appendChild(i)}},c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{c.S={};var e={},r={};c.I=(t,n)=>{n||(n=[]);var a=r[t];if(a||(a=r[t]={}),!(n.indexOf(a)>=0)){if(n.push(a),e[t])return e[t];c.o(c.S,t)||(c.S[t]={});var o=c.S[t],i="@ampath/esm-reports-app",s=(e,r,t,n)=>{var a=o[e]=o[e]||{},s=a[r];(!s||!s.loaded&&(!n!=!s.eager?n:i>s.from))&&(a[r]={get:t,from:i,eager:!!n})},l=[];return"default"===t&&(s("@openmrs/esm-framework","11.0.1-pre.5776",()=>Promise.all([c.e(961),c.e(907),c.e(478),c.e(295),c.e(31),c.e(680),c.e(435),c.e(987)]).then(()=>()=>c(9295))),s("dayjs","1.11.20",()=>c.e(353).then(()=>()=>c(4353))),s("react-i18next","16.6.6",()=>Promise.all([c.e(478),c.e(311),c.e(31)]).then(()=>()=>c(3311))),s("react-router-dom","6.30.3",()=>Promise.all([c.e(961),c.e(282),c.e(31)]).then(()=>()=>c(282))),s("react","18.3.1",()=>c.e(540).then(()=>()=>c(6540)))),e[t]=l.length?Promise.all(l).then(()=>e[t]=1):1}}})(),(()=>{c.federation.initOptions.shared={"@openmrs/esm-framework":[{version:"11.0.1-pre.5776",get:()=>Promise.all([c.e(961),c.e(907),c.e(478),c.e(295),c.e(31),c.e(680),c.e(435),c.e(987)]).then(()=>()=>c(9295)),scope:["default"],shareConfig:{eager:!1,requiredVersion:"*",strictVersion:!1,singleton:!0,layer:null}}],dayjs:[{version:"1.11.20",get:()=>c.e(353).then(()=>()=>c(4353)),scope:["default"],shareConfig:{eager:!1,requiredVersion:"1.x",strictVersion:!1,singleton:!0,layer:null}}],"react-i18next":[{version:"16.6.6",get:()=>Promise.all([c.e(478),c.e(311),c.e(31)]).then(()=>()=>c(3311)),scope:["default"],shareConfig:{eager:!1,requiredVersion:"16.x",strictVersion:!1,singleton:!0,layer:null}}],"react-router-dom":[{version:"6.30.3",get:()=>Promise.all([c.e(961),c.e(282),c.e(31)]).then(()=>()=>c(282)),scope:["default"],shareConfig:{eager:!1,requiredVersion:"6.x",strictVersion:!1,singleton:!0,layer:null}}],react:[{version:"18.3.1",get:()=>c.e(540).then(()=>()=>c(6540)),scope:["default"],shareConfig:{eager:!1,requiredVersion:"18.x",strictVersion:!1,singleton:!0,layer:null}}]},c.S={};var e={},r={};c.I=(t,n)=>c.federation.bundlerRuntime.I({shareScopeName:t,webpackRequire:c,initPromises:e,initTokens:r,initScope:n})})(),(()=>{var e;globalThis.importScripts&&(e=globalThis.location+"");var r=globalThis.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(/\/[^\/]+$/,"/"),c.p=e})(),(()=>{var e={};c.consumesLoadingData.moduleIdToConsumeDataMapping={6031:{fallback:()=>c.e(540).then(()=>()=>c(6540)),shareScope:["default"],singleton:!0,requiredVersion:"18.x",strictVersion:!1,eager:!1,layer:void 0,shareKey:"react"},6435:{fallback:()=>Promise.all([c.e(961),c.e(282)]).then(()=>()=>c(282)),shareScope:["default"],singleton:!0,requiredVersion:"6.x",strictVersion:!1,eager:!1,layer:void 0,shareKey:"react-router-dom"},7693:{fallback:()=>Promise.all([c.e(961),c.e(907),c.e(478),c.e(295),c.e(680),c.e(987)]).then(()=>()=>c(9295)),shareScope:["default"],singleton:!0,requiredVersion:"*",strictVersion:!1,eager:!1,layer:void 0,shareKey:"@openmrs/esm-framework"},7680:{fallback:()=>c.e(353).then(()=>()=>c(4353)),shareScope:["default"],singleton:!0,requiredVersion:"1.x",strictVersion:!1,eager:!1,layer:void 0,shareKey:"dayjs"},3987:{fallback:()=>c.e(311).then(()=>()=>c(3311)),shareScope:["default"],singleton:!0,requiredVersion:"16.x",strictVersion:!1,eager:!1,layer:void 0,shareKey:"react-i18next"}};var r={};c.consumesLoadingData.chunkMapping={31:[6031],410:[7693],435:[6435],680:[7680],987:[3987]},c.f.consumes=(t,n)=>{c.federation.bundlerRuntime.consumes({chunkMapping:c.consumesLoadingData.chunkMapping,installedModules:e,chunkId:t,moduleToHandlerMapping:r,promises:n,webpackRequire:c})}})(),(()=>{if("undefined"!=typeof document){var e={462:0};c.f.miniCss=(r,t)=>{e[r]?t.push(e[r]):0!==e[r]&&{295:1,953:1}[r]&&t.push(e[r]=(e=>new Promise((r,t)=>{var n=c.miniCssF(e),a=c.p+n;if(((e,r)=>{for(var t=document.getElementsByTagName("link"),n=0;n<t.length;n++){var a=(i=t[n]).getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(a===e||a===r))return i}var o=document.getElementsByTagName("style");for(n=0;n<o.length;n++){var i;if((a=(i=o[n]).getAttribute("data-href"))===e||a===r)return i}})(n,a))return r();((e,r,t,n,a)=>{var o=document.createElement("link");o.rel="stylesheet",o.type="text/css",c.nc&&(o.nonce=c.nc),o.onerror=o.onload=t=>{if(o.onerror=o.onload=null,"load"===t.type)n();else{var i=t&&t.type,s=t&&t.target&&t.target.href||r,c=new Error("Loading CSS chunk "+e+" failed.\n("+i+": "+s+")");c.name="ChunkLoadError",c.code="CSS_CHUNK_LOAD_FAILED",c.type=i,c.request=s,o.parentNode&&o.parentNode.removeChild(o),a(c)}},o.href=r,document.head.appendChild(o)})(e,a,0,r,t)}))(r).then(()=>{e[r]=0},t=>{throw delete e[r],t}))}}})(),a=c.x,o=!1,c.x=()=>{if(o||(o=!0,c(2464)),"function"==typeof a)return a();console.warn("[Module Federation] prevStartup is not a function, skipping startup execution")},(()=>{var e={462:0};c.f.j=(r,t)=>{var n=c.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else if(/^(31|435|680|987)$/.test(r))e[r]=0;else{var a=new Promise((t,a)=>n=e[r]=[t,a]);t.push(n[2]=a);var o=c.p+c.u(r),i=new Error;c.l(o,t=>{if(c.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+a+": "+o+")",i.name="ChunkLoadError",i.type=a,i.request=o,n[1](i)}},"chunk-"+r,r)}};var r=(r,t)=>{var n,a,[o,i,s]=t,l=0;if(o.some(r=>0!==e[r])){for(n in i)c.o(i,n)&&(c.m[n]=i[n]);s&&s(c)}for(r&&r(t);l<o.length;l++)a=o[l],c.o(e,a)&&e[a]&&e[a][0](),e[a]=0},t=self.webpackChunk_ampath_esm_reports_app=self.webpackChunk_ampath_esm_reports_app||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),c.x();var l=c(9421);_ampath_esm_reports_app=l})();
package/dist/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":">=2.2.0"},"extensions":[{"name":"ampath-reports-dashboard-link","component":"reportsDashboardLink","slot":"homepage-dashboard-slot","privileges":["O3 View Reports Dashboard"],"meta":{"name":"reports","slot":"ampath-reports-dashboard-slot","title":"Reports"},"online":true,"offline":true},{"component":"root","name":"ampath-reports-dashboard-root","slot":"ampath-reports-dashboard-slot","privileges":["O3 View Reports Dashboard"]}],"pages":[],"version":"1.0.0-next.63"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":">=2.2.0"},"extensions":[{"name":"ampath-reports-dashboard-link","component":"reportsDashboardLink","slot":"homepage-dashboard-slot","privileges":["O3 View Reports Dashboard"],"meta":{"name":"reports","slot":"ampath-reports-dashboard-slot","title":"Reports"},"online":true,"offline":true},{"component":"root","name":"ampath-reports-dashboard-root","slot":"ampath-reports-dashboard-slot","privileges":["O3 View Reports Dashboard"]}],"pages":[],"version":"1.0.0-next.64"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ampath/esm-reports-app",
3
- "version": "1.0.0-next.63",
3
+ "version": "1.0.0-next.64",
4
4
  "license": "MPL-2.0",
5
5
  "description": "An AMPATH application for M&E reports",
6
6
  "browser": "dist/ampath-esm-reports-app.js",
@@ -43,6 +43,8 @@
43
43
  "dependencies": {
44
44
  "@carbon/react": "^1.83.0",
45
45
  "classname": "^0.0.0",
46
+ "html-to-image": "1.11.11",
47
+ "jspdf": "^4.2.1",
46
48
  "lodash-es": "^4.17.21"
47
49
  },
48
50
  "peerDependencies": {
@@ -29,7 +29,7 @@ interface LinelistTableProps {
29
29
 
30
30
  type SortState = { header: string; direction: 'asc' | 'desc' } | null;
31
31
 
32
- const PAGE_SIZES = [25, 50, 100, 250];
32
+ const PAGE_SIZES = [25, 50, 100, 250, 500, 1000];
33
33
 
34
34
  const asText = (value: unknown) => (value === null || value === undefined ? '' : String(value));
35
35
 
@@ -25,6 +25,7 @@ import {
25
25
  monthToDateRange,
26
26
  validatePeriod,
27
27
  } from './date-range';
28
+ import { showReportError } from '../report-error';
28
29
  import { type ReportFiltersProps } from './types';
29
30
  import styles from './report-filters.scss';
30
31
 
@@ -43,6 +44,9 @@ const ReportFiltersComponent: React.FC<ReportFiltersProps> = ({
43
44
  generatedPeriod,
44
45
  onGenerate,
45
46
  onPeriodChange,
47
+ onDownloadPdf,
48
+ backLink = { label: 'All reports', to: '/' },
49
+ defaultTab = 'monthly',
46
50
  }) => {
47
51
  /* A register's breadcrumb links back here carrying the period the report was
48
52
  generated for. Seeding the controls from it matters as much as restoring
@@ -64,8 +68,9 @@ const ReportFiltersComponent: React.FC<ReportFiltersProps> = ({
64
68
  ? dayjs(urlStart).format('YYYY-MM')
65
69
  : null);
66
70
 
71
+ /* a period in the URL decides; otherwise the report's own default */
67
72
  const [activeTab, setActiveTab] = React.useState<'monthly' | 'custom'>(
68
- urlStart && urlEnd && !urlWholeMonth ? 'custom' : 'monthly',
73
+ urlStart && urlEnd ? (urlWholeMonth ? 'monthly' : 'custom') : defaultTab,
69
74
  );
70
75
 
71
76
  const [startDateString, setStartDateString] = React.useState<string>(() => urlStart ?? formatDate(new Date()));
@@ -145,6 +150,22 @@ const ReportFiltersComponent: React.FC<ReportFiltersProps> = ({
145
150
  }
146
151
  : null);
147
152
 
153
+ const [isPreparingPdf, setIsPreparingPdf] = React.useState(false);
154
+ const downloadPdf = async () => {
155
+ if (!onDownloadPdf) {
156
+ window.print();
157
+ return;
158
+ }
159
+ setIsPreparingPdf(true);
160
+ try {
161
+ await onDownloadPdf();
162
+ } catch (error) {
163
+ showReportError(`the ${reportName} PDF`, error);
164
+ } finally {
165
+ setIsPreparingPdf(false);
166
+ }
167
+ };
168
+
148
169
  const isStale = isReportGenerated && shownPeriod !== null && shownPeriod.key !== periodKey;
149
170
 
150
171
  const handleGenerate = () => {
@@ -198,7 +219,7 @@ const ReportFiltersComponent: React.FC<ReportFiltersProps> = ({
198
219
  <div className={styles.filters}>
199
220
  <Breadcrumb noTrailingSlash className={styles.breadcrumb}>
200
221
  <BreadcrumbItem>
201
- <Link to="/">All reports</Link>
222
+ <Link to={backLink.to}>{backLink.label}</Link>
202
223
  </BreadcrumbItem>
203
224
  {/* The report name doubles as the page heading, so it stays an `h3`
204
225
  rather than being repeated in a separate title row. */}
@@ -305,8 +326,8 @@ const ReportFiltersComponent: React.FC<ReportFiltersProps> = ({
305
326
  <div className={styles.actionButtons}>
306
327
  {/* Only offered once there is something on screen to put on paper */}
307
328
  {isReportGenerated && !isLoading && (
308
- <Button kind="tertiary" size="sm" renderIcon={Download} onClick={() => window.print()}>
309
- Download PDF
329
+ <Button kind="tertiary" size="sm" renderIcon={Download} onClick={downloadPdf} disabled={isPreparingPdf}>
330
+ {isPreparingPdf ? 'Preparing PDF…' : 'Download PDF'}
310
331
  </Button>
311
332
  )}
312
333
  <Button size="sm" renderIcon={ChartColumn} onClick={handleGenerate} disabled={isLoading || !isValid}>
@@ -63,4 +63,17 @@ export interface ReportFiltersProps {
63
63
  * than only once figures have been fetched for it.
64
64
  */
65
65
  onPeriodChange?: (period: ReportPeriod) => void;
66
+ /**
67
+ * Saves the report as a PDF file. Without it, Download PDF opens the
68
+ * browser's print dialog on the report's print layout.
69
+ */
70
+ onDownloadPdf?: () => Promise<void>;
71
+ /**
72
+ * The period type a `both` filter bar opens on when the URL carries no
73
+ * period: `monthly` (last month, the reports' default) or `custom` (today to
74
+ * today, the registers' default).
75
+ */
76
+ defaultTab?: 'monthly' | 'custom';
77
+ /** Where the breadcrumb leads back to; defaults to All reports on the landing page */
78
+ backLink?: { label: string; to: string };
66
79
  }
@@ -0,0 +1,59 @@
1
+ /** A4 portrait, in millimetres */
2
+ const A4_WIDTH_MM = 210;
3
+ const A4_HEIGHT_MM = 297;
4
+
5
+ /** Capture resolution: 3 device pixels per CSS pixel keeps 5.5pt type sharp */
6
+ const PIXEL_RATIO = 3;
7
+
8
+ /** Waits for the browser to lay out and paint a change */
9
+ const nextPaint = () =>
10
+ new Promise<void>((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
11
+
12
+ /**
13
+ * Saves an A4 sheet as a one-page A4 PDF file.
14
+ *
15
+ * The sheet is captured as drawn on screen and placed on the page within the
16
+ * given margin, scaled down only if it would not otherwise fit, so the file is
17
+ * the form itself rather than the browser's print layout (no headers, footers
18
+ * or print dialog).
19
+ *
20
+ * What is captured is a copy laid out off screen at paper size, without the
21
+ * on-screen magnification (`--page-zoom`), so the sheet the user is looking at
22
+ * never changes while the file is prepared -- and a sheet in a hidden tab can
23
+ * be saved without showing it.
24
+ */
25
+ export async function downloadSheetPdf(sheet: HTMLElement, fileName: string, marginMm = 8): Promise<void> {
26
+ const [{ toCanvas }, { jsPDF }] = await Promise.all([import('html-to-image'), import('jspdf')]);
27
+
28
+ const stage = document.createElement('div');
29
+ stage.setAttribute('aria-hidden', 'true');
30
+ Object.assign(stage.style, { position: 'fixed', top: '0', left: '-100000px', pointerEvents: 'none' });
31
+ const copy = sheet.cloneNode(true) as HTMLElement;
32
+ copy.style.setProperty('--page-zoom', '1');
33
+ copy.style.margin = '0';
34
+ stage.appendChild(copy);
35
+ document.body.appendChild(stage);
36
+
37
+ let canvas: HTMLCanvasElement;
38
+ try {
39
+ await nextPaint();
40
+ canvas = await toCanvas(copy, {
41
+ pixelRatio: PIXEL_RATIO,
42
+ backgroundColor: '#fff',
43
+ width: copy.offsetWidth,
44
+ height: copy.offsetHeight,
45
+ });
46
+ } finally {
47
+ stage.remove();
48
+ }
49
+
50
+ const maxWidth = A4_WIDTH_MM - 2 * marginMm;
51
+ const maxHeight = A4_HEIGHT_MM - 2 * marginMm;
52
+ const aspect = canvas.width / canvas.height;
53
+ const width = Math.min(maxWidth, maxHeight * aspect);
54
+ const height = width / aspect;
55
+
56
+ const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4', compress: true });
57
+ pdf.addImage(canvas, 'PNG', (A4_WIDTH_MM - width) / 2, marginMm, width, height, undefined, 'FAST');
58
+ pdf.save(fileName);
59
+ }
@@ -1,2 +1,3 @@
1
1
  export { default as ReportPage } from './report-page.component';
2
2
  export * from './use-page-scale';
3
+ export * from './download-sheet-pdf';
@@ -1,10 +1,17 @@
1
- import React, { useMemo, useState } from 'react';
2
- import { useNavigate } from 'react-router-dom';
3
- import { Button, ClickableTile, Layer, Search, Tag } from '@carbon/react';
4
- import { ArrowRight, Calendar, Location, Report } from '@carbon/react/icons';
1
+ import React, { useState } from 'react';
2
+ import { useNavigate, useSearchParams } from 'react-router-dom';
3
+ import { Button, ClickableTile, Layer, Search, Tab, TabList, TabPanel, TabPanels, Tabs, Tag } from '@carbon/react';
4
+ import { ArrowRight, DocumentMultiple_01, Report, type CarbonIconType } from '@carbon/react/icons';
5
5
  import { formatDate, useSession } from '@openmrs/esm-framework';
6
6
 
7
- import { filterCategories, reportCategories, totalReportCount, type ReportDefinition } from './report-catalog';
7
+ import { registerCategories, totalRegisterCount } from '../registers/register-catalog';
8
+ import {
9
+ filterCategories,
10
+ reportCategories,
11
+ totalReportCount,
12
+ type ReportCategory,
13
+ type ReportDefinition,
14
+ } from './report-catalog';
8
15
  import styles from './reports-dashboard.module.scss';
9
16
 
10
17
  interface ReportsDashboardProps {}
@@ -12,15 +19,26 @@ interface ReportsDashboardProps {}
12
19
  const ReportsDashboard: React.FC<ReportsDashboardProps> = () => {
13
20
  const navigate = useNavigate();
14
21
  const session = useSession();
15
- const [searchTerm, setSearchTerm] = useState<string>('');
22
+ /* each tab keeps its own search */
23
+ const [reportSearch, setReportSearch] = useState<string>('');
24
+ const [registerSearch, setRegisterSearch] = useState<string>('');
25
+
26
+ /* Reports first, Registers second; the open tab is kept in the URL */
27
+ const [searchParams, setSearchParams] = useSearchParams();
28
+ const selectedTab = searchParams.get('tab') === 'registers' ? 1 : 0;
29
+ const selectTab = ({ selectedIndex }: { selectedIndex: number }) => {
30
+ const next = new URLSearchParams(searchParams);
31
+ if (selectedIndex === 1) {
32
+ next.set('tab', 'registers');
33
+ } else {
34
+ next.delete('tab');
35
+ }
36
+ setSearchParams(next, { replace: true });
37
+ };
16
38
 
17
39
  const facilityName = session?.sessionLocation?.display;
18
40
  const today = formatDate(new Date(), { mode: 'standard', time: false, noToday: true });
19
41
 
20
- const visibleCategories = useMemo(() => filterCategories(reportCategories, searchTerm), [searchTerm]);
21
- const matchCount = visibleCategories.reduce((count, category) => count + category.reports.length, 0);
22
- const isSearching = searchTerm.trim().length > 0;
23
-
24
42
  const renderReportTile = (report: ReportDefinition, tone: string) => {
25
43
  const Icon = report.icon;
26
44
 
@@ -44,68 +62,137 @@ const ReportsDashboard: React.FC<ReportsDashboardProps> = () => {
44
62
  );
45
63
  };
46
64
 
47
- return (
48
- <div className={styles.dashboard}>
49
- <header className={styles.header}>
50
- <div className={styles.headerIcon}>
51
- <Report size={20} />
52
- </div>
53
- <h3 className={styles.headerTitle}>Reports</h3>
54
- <div className={styles.headerMeta}>
55
- {facilityName && (
56
- <span className={styles.metaItem}>
57
- <Location size={16} />
58
- {facilityName}
59
- </span>
60
- )}
61
- <span className={styles.metaItem}>
62
- <Calendar size={16} />
63
- {today}
64
- </span>
65
+ const renderCategory = (category: ReportCategory) => (
66
+ <section key={category.id} className={styles.category}>
67
+ <div className={styles.categoryHeader} data-tone={category.tone}>
68
+ <h5 className={styles.categoryTitle}>{category.title}</h5>
69
+ <Tag size="sm" type="outline">
70
+ {category.reports.length}
71
+ </Tag>
72
+ </div>
73
+ <div className={styles.grid}>{category.reports.map((report) => renderReportTile(report, category.tone))}</div>
74
+ </section>
75
+ );
76
+
77
+ /** A tab's list: search row, then its categories, or a message when nothing matches */
78
+ const renderCatalog = ({
79
+ id,
80
+ noun,
81
+ categories,
82
+ total,
83
+ term,
84
+ setTerm,
85
+ icon: Icon,
86
+ hint,
87
+ }: {
88
+ id: string;
89
+ noun: string;
90
+ categories: ReportCategory[];
91
+ total: number;
92
+ term: string;
93
+ setTerm: (term: string) => void;
94
+ icon: CarbonIconType;
95
+ hint: string;
96
+ }) => {
97
+ const visible = filterCategories(categories, term);
98
+ const matches = visible.reduce((count, category) => count + category.reports.length, 0);
99
+ const isSearching = term.trim().length > 0;
100
+ const label = `Search ${noun}`;
101
+ /* "1 register", "10 reports" */
102
+ const counted = (n: number) => (n === 1 ? noun.replace(/s$/, '') : noun);
103
+
104
+ return (
105
+ <>
106
+ <div className={styles.toolbar}>
107
+ <Layer className={styles.searchLayer}>
108
+ <Search
109
+ id={id}
110
+ labelText={label}
111
+ placeholder={label}
112
+ size="md"
113
+ value={term}
114
+ onChange={(event) => setTerm(event.target.value)}
115
+ onClear={() => setTerm('')}
116
+ />
117
+ </Layer>
118
+ <p className={styles.resultCount}>
119
+ {isSearching ? `${matches} of ${total} ${counted(total)}` : `${total} ${counted(total)} available`}
120
+ </p>
65
121
  </div>
66
- </header>
67
122
 
68
- <div className={styles.toolbar}>
69
- <Layer className={styles.searchLayer}>
70
- <Search
71
- id="reports-search"
72
- labelText="Search reports"
73
- placeholder="Search reports"
74
- size="sm"
75
- value={searchTerm}
76
- onChange={(event) => setSearchTerm(event.target.value)}
77
- onClear={() => setSearchTerm('')}
78
- />
79
- </Layer>
80
- <p className={styles.resultCount}>
81
- {isSearching ? `${matchCount} of ${totalReportCount} reports` : `${totalReportCount} reports available`}
82
- </p>
83
- </div>
123
+ {visible.length > 0 ? (
124
+ visible.map(renderCategory)
125
+ ) : (
126
+ <Layer className={styles.emptyState}>
127
+ <Icon size={32} className={styles.emptyStateIcon} />
128
+ <h5>
129
+ No {noun} match &ldquo;{term}&rdquo;
130
+ </h5>
131
+ <p>{hint}</p>
132
+ <Button kind="ghost" size="sm" onClick={() => setTerm('')}>
133
+ Clear search
134
+ </Button>
135
+ </Layer>
136
+ )}
137
+ </>
138
+ );
139
+ };
84
140
 
85
- {visibleCategories.length > 0 ? (
86
- visibleCategories.map((category) => (
87
- <section key={category.id} className={styles.category}>
88
- <div className={styles.categoryHeader} data-tone={category.tone}>
89
- <h5 className={styles.categoryTitle}>{category.title}</h5>
90
- <Tag size="sm" type="outline">
91
- {category.reports.length}
92
- </Tag>
93
- </div>
94
- <div className={styles.grid}>
95
- {category.reports.map((report) => renderReportTile(report, category.tone))}
96
- </div>
97
- </section>
98
- ))
99
- ) : (
100
- <Layer className={styles.emptyState}>
101
- <Report size={32} className={styles.emptyStateIcon} />
102
- <h5>No reports match &ldquo;{searchTerm}&rdquo;</h5>
103
- <p>Try a form number such as 731, or a service such as immunization.</p>
104
- <Button kind="ghost" size="sm" onClick={() => setSearchTerm('')}>
105
- Clear search
106
- </Button>
107
- </Layer>
108
- )}
141
+ return (
142
+ <div className={styles.dashboard}>
143
+ {/* The facility and date sit at the right end of the tab row */}
144
+ <div className={styles.tabsArea}>
145
+ <p className={styles.headerMeta}>{[facilityName, today].filter(Boolean).join(' · ')}</p>
146
+ <Tabs selectedIndex={selectedTab} onChange={selectTab}>
147
+ <TabList aria-label="Reports and registers" className={styles.tabList}>
148
+ <Tab>
149
+ <span className={styles.tabLabel}>
150
+ <Report size={16} />
151
+ Reports
152
+ <Tag size="sm" type="gray" className={styles.tabCount}>
153
+ {totalReportCount}
154
+ </Tag>
155
+ </span>
156
+ </Tab>
157
+ <Tab>
158
+ <span className={styles.tabLabel}>
159
+ <DocumentMultiple_01 size={16} />
160
+ Registers
161
+ <Tag size="sm" type="gray" className={styles.tabCount}>
162
+ {totalRegisterCount}
163
+ </Tag>
164
+ </span>
165
+ </Tab>
166
+ </TabList>
167
+ <TabPanels>
168
+ <TabPanel className={styles.tabPanel}>
169
+ {renderCatalog({
170
+ id: 'reports-search',
171
+ noun: 'reports',
172
+ categories: reportCategories,
173
+ total: totalReportCount,
174
+ term: reportSearch,
175
+ setTerm: setReportSearch,
176
+ icon: Report,
177
+ hint: 'Try a form number such as 731, or a service such as immunization.',
178
+ })}
179
+ </TabPanel>
180
+ <TabPanel className={styles.tabPanel}>
181
+ {/* Registers, from src/registers, listed and searched as the reports are */}
182
+ {renderCatalog({
183
+ id: 'registers-search',
184
+ noun: 'registers',
185
+ categories: registerCategories,
186
+ total: totalRegisterCount,
187
+ term: registerSearch,
188
+ setTerm: setRegisterSearch,
189
+ icon: DocumentMultiple_01,
190
+ hint: 'Try a register number such as 362, or a service such as HTS.',
191
+ })}
192
+ </TabPanel>
193
+ </TabPanels>
194
+ </Tabs>
195
+ </div>
109
196
  </div>
110
197
  );
111
198
  };