@openmrs/esm-report-builder 0.1.1-pre.87

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 (551) hide show
  1. package/.eslintignore +5 -0
  2. package/.eslintrc.js +19 -0
  3. package/.prettierrc +8 -0
  4. package/.tx/config +12 -0
  5. package/LICENSE +401 -0
  6. package/README.md +336 -0
  7. package/__mocks__/react-i18next.js +12 -0
  8. package/dist/162.js +1 -0
  9. package/dist/162.js.map +1 -0
  10. package/dist/184.js +2 -0
  11. package/dist/184.js.LICENSE.txt +14 -0
  12. package/dist/184.js.map +1 -0
  13. package/dist/242.js +2 -0
  14. package/dist/242.js.LICENSE.txt +21 -0
  15. package/dist/242.js.map +1 -0
  16. package/dist/253.js +1 -0
  17. package/dist/253.js.map +1 -0
  18. package/dist/300.js +1 -0
  19. package/dist/311.js +1 -0
  20. package/dist/311.js.map +1 -0
  21. package/dist/469.js +2 -0
  22. package/dist/469.js.LICENSE.txt +45 -0
  23. package/dist/469.js.map +1 -0
  24. package/dist/478.js +2 -0
  25. package/dist/478.js.LICENSE.txt +9 -0
  26. package/dist/478.js.map +1 -0
  27. package/dist/539.js +1 -0
  28. package/dist/539.js.map +1 -0
  29. package/dist/540.js +2 -0
  30. package/dist/540.js.LICENSE.txt +9 -0
  31. package/dist/540.js.map +1 -0
  32. package/dist/669.js +1 -0
  33. package/dist/669.js.map +1 -0
  34. package/dist/710.js +1 -0
  35. package/dist/710.js.map +1 -0
  36. package/dist/729.js +1 -0
  37. package/dist/729.js.map +1 -0
  38. package/dist/838.js +2 -0
  39. package/dist/838.js.LICENSE.txt +9 -0
  40. package/dist/838.js.map +1 -0
  41. package/dist/917.js +1 -0
  42. package/dist/917.js.map +1 -0
  43. package/dist/961.js +2 -0
  44. package/dist/961.js.LICENSE.txt +19 -0
  45. package/dist/961.js.map +1 -0
  46. package/dist/main.js +1 -0
  47. package/dist/main.js.map +1 -0
  48. package/dist/openmrs-esm-report-builder.js +1 -0
  49. package/dist/openmrs-esm-report-builder.js.buildmanifest.json +530 -0
  50. package/dist/openmrs-esm-report-builder.js.map +1 -0
  51. package/dist/routes.json +1 -0
  52. package/e2e/core/env.ts +5 -0
  53. package/e2e/core/global-setup.ts +34 -0
  54. package/e2e/core/test.ts +21 -0
  55. package/e2e/pages/app-shell.page.ts +34 -0
  56. package/e2e/pages/etl-sources.page.ts +35 -0
  57. package/e2e/pages/report-sections.page.ts +20 -0
  58. package/e2e/pages/section-preview.modal.ts +29 -0
  59. package/e2e/specs/etl-sources.spec.ts +51 -0
  60. package/e2e/specs/navigation.spec.ts +13 -0
  61. package/e2e/specs/section-preview-validation.spec.ts +38 -0
  62. package/e2e/specs/section-preview.spec.ts +94 -0
  63. package/e2e/support/github/Dockerfile +22 -0
  64. package/e2e/support/github/Dockerfile.dockerignore +13 -0
  65. package/e2e/support/github/docker-compose.yml +31 -0
  66. package/e2e/support/github/run-e2e-docker-env.sh +131 -0
  67. package/e2e/support/github/spa-assemble-config.json +9 -0
  68. package/e2e/tsconfig.json +11 -0
  69. package/example.env +5 -0
  70. package/jest.config.js +28 -0
  71. package/linelist_report_builder_design_spec.md +816 -0
  72. package/package.json +111 -0
  73. package/playwright.config.ts +28 -0
  74. package/routes.json +22 -0
  75. package/src/__debug__/all-designs.test.tsx +30 -0
  76. package/src/admin-card-link.extension.module.scss +55 -0
  77. package/src/admin-card-link.extension.tsx +24 -0
  78. package/src/components/admin/admin-page.component.tsx +75 -0
  79. package/src/components/admin/age-categories-page.component.tsx +109 -0
  80. package/src/components/admin/age-groups-page.component.tsx +146 -0
  81. package/src/components/admin/etl-browser/columns-tab.component.tsx +80 -0
  82. package/src/components/admin/etl-browser/etl-browser-page.component.tsx +309 -0
  83. package/src/components/admin/etl-browser/etl-browser.component.scss +424 -0
  84. package/src/components/admin/etl-browser/metadata-tab.component.tsx +65 -0
  85. package/src/components/admin/etl-browser/preview-grid.component.tsx +189 -0
  86. package/src/components/admin/etl-browser/relationships-tab.component.tsx +21 -0
  87. package/src/components/admin/etl-browser/sources-tree.component.tsx +118 -0
  88. package/src/components/admin/etl-browser/table-detail.component.tsx +124 -0
  89. package/src/components/admin/etl-browser/table-info-strip.component.tsx +51 -0
  90. package/src/components/admin/etl-browser/table-list.component.tsx +136 -0
  91. package/src/components/admin/etl-browser/use-table-preview.ts +47 -0
  92. package/src/components/admin/etl-sources-page.component.tsx +355 -0
  93. package/src/components/admin/etl-tasks-page.component.scss +370 -0
  94. package/src/components/admin/etl-tasks-page.component.tsx +768 -0
  95. package/src/components/admin/report-categories-page.component.tsx +267 -0
  96. package/src/components/admin/report-library-page.component.tsx +551 -0
  97. package/src/components/ai-support/ai-assist-button.component.tsx +30 -0
  98. package/src/components/ai-support/ai-assist-modal.component.tsx +81 -0
  99. package/src/components/ai-support/ai.service.ts +21 -0
  100. package/src/components/ai-support/ai.types.ts +12 -0
  101. package/src/components/app-shell/report-builder-shell.component.tsx +242 -0
  102. package/src/components/app-shell/report-builder-shell.scss +18 -0
  103. package/src/components/dashboards/dashboard-config.schema.ts +97 -0
  104. package/src/components/dashboards/dashboard-form-modal.component.tsx +150 -0
  105. package/src/components/dashboards/dashboards-admin.scss +62 -0
  106. package/src/components/dashboards/dashboards-page.component.tsx +153 -0
  107. package/src/components/dashboards/dashboards-table.component.tsx +130 -0
  108. package/src/components/dashboards/sections/dashboard-autoinclude.section.tsx +75 -0
  109. package/src/components/dashboards/sections/dashboard-basics.section.tsx +80 -0
  110. package/src/components/dashboards/sections/dashboard-json.section.tsx +79 -0
  111. package/src/components/dashboards/sections/dashboard-sections-editor.section.tsx +130 -0
  112. package/src/components/dashboards/sections/dashboard-widgets-editor.section.tsx +184 -0
  113. package/src/components/data-themes/data-theme-form.component.tsx +59 -0
  114. package/src/components/data-themes/data-theme-modal.component.tsx +349 -0
  115. package/src/components/data-themes/data-themes-page.component.tsx +139 -0
  116. package/src/components/data-themes/data-themes-table.component.tsx +98 -0
  117. package/src/components/data-themes/icon-registry.ts +35 -0
  118. package/src/components/data-themes/sections/data-theme-basics.section.tsx +63 -0
  119. package/src/components/data-themes/sections/data-theme-condition-columns.section.tsx +397 -0
  120. package/src/components/data-themes/sections/data-theme-fields-editor.section.tsx +125 -0
  121. package/src/components/data-themes/sections/data-theme-metadata.section.tsx +245 -0
  122. package/src/components/data-themes/sections/data-theme-preview.section.tsx +115 -0
  123. package/src/components/data-themes/sections/data-theme-source.section.tsx +184 -0
  124. package/src/components/data-visualizer/components/cqi-components/cqi-data-table.component.tsx +214 -0
  125. package/src/components/data-visualizer/components/cqi-components/cqi-elements.ts +203 -0
  126. package/src/components/data-visualizer/components/cqi-components/detail.component.tsx +110 -0
  127. package/src/components/data-visualizer/components/cqi-components/detail.scss +22 -0
  128. package/src/components/data-visualizer/components/data-table/data-table.component.tsx +208 -0
  129. package/src/components/data-visualizer/components/data-table/data-tables.scss +206 -0
  130. package/src/components/data-visualizer/components/empty-state/empty-state-illustration.component.tsx +53 -0
  131. package/src/components/data-visualizer/components/header/header.component.tsx +43 -0
  132. package/src/components/data-visualizer/components/header/header.scss +71 -0
  133. package/src/components/data-visualizer/components/model/confirm.component.tsx +40 -0
  134. package/src/components/data-visualizer/components/panel/panel.component.tsx +20 -0
  135. package/src/components/data-visualizer/components/panel/panel.scss +25 -0
  136. package/src/components/data-visualizer/components/popover/modifier-panel.tsx +53 -0
  137. package/src/components/data-visualizer/constants.ts +445 -0
  138. package/src/components/data-visualizer/data-visualizer-illustration.component.tsx +31 -0
  139. package/src/components/data-visualizer/data-visualizer.component.tsx +1935 -0
  140. package/src/components/data-visualizer/data-visualizer.resource.ts +462 -0
  141. package/src/components/data-visualizer/data-visualizer.scss +449 -0
  142. package/src/components/data-visualizer/declarations.d.ts +131 -0
  143. package/src/components/data-visualizer/parameter-inputs/boolean-parameter-input.component.tsx +34 -0
  144. package/src/components/data-visualizer/parameter-inputs/concept-parameter-input.component.tsx +81 -0
  145. package/src/components/data-visualizer/parameter-inputs/date-parameter-input.component.tsx +110 -0
  146. package/src/components/data-visualizer/parameter-inputs/date-range-input.component.scss +47 -0
  147. package/src/components/data-visualizer/parameter-inputs/date-range-input.component.tsx +228 -0
  148. package/src/components/data-visualizer/parameter-inputs/identifier-type-parameter-input.component.tsx +69 -0
  149. package/src/components/data-visualizer/parameter-inputs/list-parameter-input.component.tsx +73 -0
  150. package/src/components/data-visualizer/parameter-inputs/location-parameter-input.component.tsx +81 -0
  151. package/src/components/data-visualizer/parameter-inputs/number-parameter-input.component.tsx +40 -0
  152. package/src/components/data-visualizer/parameter-inputs/person-attribute-parameter-input.component.tsx +71 -0
  153. package/src/components/data-visualizer/parameter-inputs/text-parameter-input.component.tsx +52 -0
  154. package/src/components/data-visualizer/report-parameter-modal.component.tsx +383 -0
  155. package/src/components/data-visualizer/types.ts +206 -0
  156. package/src/components/etl-monitor/builder/builder-state-machine.ts +381 -0
  157. package/src/components/etl-monitor/builder/design-registry.tsx +139 -0
  158. package/src/components/etl-monitor/builder/etl-monitor-builder-context.tsx +702 -0
  159. package/src/components/etl-monitor/builder/etl-monitor-builder-modal.component.tsx +461 -0
  160. package/src/components/etl-monitor/builder/etl-monitor-builder-modal.scss +256 -0
  161. package/src/components/etl-monitor/builder/etl-monitor-builder-page.component.tsx +387 -0
  162. package/src/components/etl-monitor/builder/etl-monitor-builder-page.scss +976 -0
  163. package/src/components/etl-monitor/builder/generated-config-panel.component.tsx +168 -0
  164. package/src/components/etl-monitor/builder/generated-config-panel.scss +198 -0
  165. package/src/components/etl-monitor/builder/index.ts +5 -0
  166. package/src/components/etl-monitor/builder/monitor-preview.tsx +124 -0
  167. package/src/components/etl-monitor/builder/steps/data-source-step.component.tsx +667 -0
  168. package/src/components/etl-monitor/builder/steps/data-source-step.scss +284 -0
  169. package/src/components/etl-monitor/builder/steps/design-samples.ts +278 -0
  170. package/src/components/etl-monitor/builder/steps/design-step.component.tsx +299 -0
  171. package/src/components/etl-monitor/builder/steps/design-step.scss +479 -0
  172. package/src/components/etl-monitor/builder/steps/fields-step.component.tsx +859 -0
  173. package/src/components/etl-monitor/builder/steps/fields-step.scss +459 -0
  174. package/src/components/etl-monitor/builder/steps/general-step.component.tsx +288 -0
  175. package/src/components/etl-monitor/builder/steps/general-step.scss +103 -0
  176. package/src/components/etl-monitor/builder/steps/index.ts +5 -0
  177. package/src/components/etl-monitor/builder/steps/preview-step.component.tsx +245 -0
  178. package/src/components/etl-monitor/builder/steps/preview-step.scss +236 -0
  179. package/src/components/etl-monitor/etl-monitor-card-shell.component.tsx +154 -0
  180. package/src/components/etl-monitor/etl-monitor-card-shell.scss +103 -0
  181. package/src/components/etl-monitor/etl-monitor-dashboard.component.tsx +227 -0
  182. package/src/components/etl-monitor/etl-monitor-dashboard.scss +148 -0
  183. package/src/components/etl-monitor/etl-monitor-status-card.component.tsx +192 -0
  184. package/src/components/etl-monitor/etl-monitors-page.component.tsx +621 -0
  185. package/src/components/etl-monitor/renderers/DetailsRenderer.tsx +2 -0
  186. package/src/components/etl-monitor/renderers/ErrorLogRenderer.tsx +2 -0
  187. package/src/components/etl-monitor/renderers/EtlMonitorWidget.tsx +97 -0
  188. package/src/components/etl-monitor/renderers/MetricsGridRenderer.tsx +2 -0
  189. package/src/components/etl-monitor/renderers/MonitorRenderer.tsx +175 -0
  190. package/src/components/etl-monitor/renderers/ProgressRenderer.tsx +2 -0
  191. package/src/components/etl-monitor/renderers/StatusCardRenderer.tsx +2 -0
  192. package/src/components/etl-monitor/renderers/SummaryCardRenderer.tsx +2 -0
  193. package/src/components/etl-monitor/renderers/TableRenderer.tsx +2 -0
  194. package/src/components/etl-monitor/renderers/component-icons.tsx +33 -0
  195. package/src/components/etl-monitor/renderers/components/details-renderer.tsx +195 -0
  196. package/src/components/etl-monitor/renderers/components/error-log-renderer.tsx +104 -0
  197. package/src/components/etl-monitor/renderers/components/index.ts +6 -0
  198. package/src/components/etl-monitor/renderers/components/log-renderer.tsx +86 -0
  199. package/src/components/etl-monitor/renderers/components/metrics-grid-renderer.tsx +133 -0
  200. package/src/components/etl-monitor/renderers/components/progress-renderer.tsx +188 -0
  201. package/src/components/etl-monitor/renderers/components/status-card-renderer.tsx +247 -0
  202. package/src/components/etl-monitor/renderers/components/summary-card-renderer.tsx +160 -0
  203. package/src/components/etl-monitor/renderers/components/table-renderer.tsx +175 -0
  204. package/src/components/etl-monitor/renderers/components/time-series-renderer.tsx +310 -0
  205. package/src/components/etl-monitor/renderers/data-transformer.ts +361 -0
  206. package/src/components/etl-monitor/renderers/index.ts +11 -0
  207. package/src/components/etl-monitor/renderers/legacy-monitor-renderer.tsx +69 -0
  208. package/src/components/etl-monitor/renderers/monitor-renderer.tsx +6 -0
  209. package/src/components/etl-monitor/renderers/monitor-renderers.scss +1621 -0
  210. package/src/components/etl-monitor/renderers/monitor-widget-card.component.tsx +54 -0
  211. package/src/components/etl-monitor/renderers/monitor-widget-card.scss +16 -0
  212. package/src/components/etl-monitor/renderers/v2-monitor-renderer.tsx +227 -0
  213. package/src/components/import-export/artifact-groups.ts +153 -0
  214. package/src/components/import-export/export-report-modal.component.tsx +265 -0
  215. package/src/components/import-export/import-export-page.component.tsx +610 -0
  216. package/src/components/import-export/import-export.styles.scss +825 -0
  217. package/src/components/import-export/import-package-modal.component.tsx +401 -0
  218. package/src/components/import-export/index.ts +3 -0
  219. package/src/components/indicators/README.md +24 -0
  220. package/src/components/indicators/base-indicator-basic-fields.component.tsx +18 -0
  221. package/src/components/indicators/base-indicator-basics.section.tsx +54 -0
  222. package/src/components/indicators/base-indicator-countby.section.tsx +25 -0
  223. package/src/components/indicators/base-indicator-criteria.section.tsx +83 -0
  224. package/src/components/indicators/base-indicator-details-form.component.tsx +80 -0
  225. package/src/components/indicators/base-indicator-theme-unit-fields.component.tsx +39 -0
  226. package/src/components/indicators/create-base-indicator-modal.component.tsx +623 -0
  227. package/src/components/indicators/create-composite-base-indicator-modal.component.tsx +295 -0
  228. package/src/components/indicators/create-custom-indicator-modal.component.tsx +548 -0
  229. package/src/components/indicators/create-final-indicator-modal.component.tsx +285 -0
  230. package/src/components/indicators/custom-condition-input.component.tsx +310 -0
  231. package/src/components/indicators/diagnosis-filters-form.component.tsx +101 -0
  232. package/src/components/indicators/disaggregation-panel.component.tsx +93 -0
  233. package/src/components/indicators/handler/concept-search-multiselect.component.tsx +153 -0
  234. package/src/components/indicators/handler/question-answer-concept-search.component.tsx +336 -0
  235. package/src/components/indicators/indicator-run-preview-modal.component.tsx +391 -0
  236. package/src/components/indicators/indicator-search-select.component.tsx +297 -0
  237. package/src/components/indicators/indicator-status-tag.component.tsx +9 -0
  238. package/src/components/indicators/indicators-page.component.tsx +673 -0
  239. package/src/components/indicators/indicators-page.scss +121 -0
  240. package/src/components/indicators/indicators-table.component.tsx +188 -0
  241. package/src/components/indicators/preview-table.component.tsx +31 -0
  242. package/src/components/indicators/sections/composite-indicator-basics.section.tsx +36 -0
  243. package/src/components/indicators/sections/composite-indicator-picker.section.tsx +116 -0
  244. package/src/components/indicators/sections/composite-indicator-sql-preview.section.tsx +31 -0
  245. package/src/components/indicators/sections/custom-indicator-basics.section.tsx +65 -0
  246. package/src/components/indicators/sections/custom-indicator-disaggregation.section.tsx +93 -0
  247. package/src/components/indicators/sections/custom-indicator-filters.section.tsx +203 -0
  248. package/src/components/indicators/sections/custom-indicator-population.section.tsx +107 -0
  249. package/src/components/indicators/sections/custom-indicator-sql-preview.section.tsx +108 -0
  250. package/src/components/indicators/sections/final-indicator-basics.section.tsx +46 -0
  251. package/src/components/indicators/sections/final-indicator-disaggregation.section.tsx +47 -0
  252. package/src/components/indicators/sections/final-indicator-picker.section.tsx +60 -0
  253. package/src/components/indicators/sections/final-indicator-preview.section.tsx +20 -0
  254. package/src/components/indicators/sections/final-indicator-results-preview.section.tsx +65 -0
  255. package/src/components/indicators/sections/indicator-basics.section.tsx +40 -0
  256. package/src/components/indicators/sections/indicator-conditions.section.tsx +279 -0
  257. package/src/components/indicators/sections/indicator-sql-preview.section.tsx +63 -0
  258. package/src/components/indicators/sections/indicator-theme.section.tsx +48 -0
  259. package/src/components/indicators/sql-preview.component.tsx +19 -0
  260. package/src/components/indicators/tag-input.component.tsx +177 -0
  261. package/src/components/indicators/types/base-indicator-form.types.ts +17 -0
  262. package/src/components/indicators/types/base-indicator-theme.constants.ts +8 -0
  263. package/src/components/indicators/types/composite-indicator.types.ts +27 -0
  264. package/src/components/indicators/types/condition-ui.types.ts +11 -0
  265. package/src/components/indicators/types/custom-indicator.types.ts +161 -0
  266. package/src/components/indicators/types/data-theme-config.types.ts +88 -0
  267. package/src/components/indicators/types/indicator-types.ts +57 -0
  268. package/src/components/indicators/types/sql-builders.ts +43 -0
  269. package/src/components/indicators/utils/composite-indicator-sql.utils.test.ts +143 -0
  270. package/src/components/indicators/utils/composite-indicator-sql.utils.ts +426 -0
  271. package/src/components/indicators/utils/concept-preload.utils.ts +21 -0
  272. package/src/components/indicators/utils/custom-indicator-interpreter.test.ts +493 -0
  273. package/src/components/indicators/utils/custom-indicator-interpreter.ts +702 -0
  274. package/src/components/indicators/utils/final-indicator-sql.utils.ts +190 -0
  275. package/src/components/indicators/utils/indicator-conditions-hydration.utils.ts +254 -0
  276. package/src/components/indicators/utils/indicator-sql-resolution.utils.ts +204 -0
  277. package/src/components/indicators/utils/indicator-sql.utils.ts +721 -0
  278. package/src/components/indicators/utils/population-sql.compiler.test.ts +999 -0
  279. package/src/components/indicators/utils/population-sql.compiler.ts +858 -0
  280. package/src/components/landing/landing-action-item.component.tsx +50 -0
  281. package/src/components/landing/landing-action-list.component.tsx +12 -0
  282. package/src/components/landing/landing-activity-list.component.tsx +47 -0
  283. package/src/components/landing/landing-footer-grid.component.tsx +45 -0
  284. package/src/components/landing/landing-hero.component.tsx +18 -0
  285. package/src/components/landing/landing-section-card.component.tsx +33 -0
  286. package/src/components/landing/report-builder-landing-page.component.tsx +186 -0
  287. package/src/components/landing/report-builder-landing-page.scss +131 -0
  288. package/src/components/legacy-reports/legacy-report-detail-page.component.tsx +300 -0
  289. package/src/components/legacy-reports/legacy-report-editor-page.component.tsx +324 -0
  290. package/src/components/legacy-reports/legacy-report-upload-modal.component.tsx +307 -0
  291. package/src/components/legacy-reports/legacy-reports-page.component.tsx +206 -0
  292. package/src/components/legacy-reports/legacy-reports-table.component.tsx +154 -0
  293. package/src/components/legacy-reports/tabs/legacy-report-datasets-tab.component.tsx +344 -0
  294. package/src/components/legacy-reports/tabs/legacy-report-dimensions-tab.component.tsx +590 -0
  295. package/src/components/legacy-reports/tabs/legacy-report-indicators-tab.component.tsx +490 -0
  296. package/src/components/legacy-reports/tabs/legacy-report-json-preview-tab.component.tsx +272 -0
  297. package/src/components/legacy-reports/tabs/legacy-report-overview-tab.component.tsx +218 -0
  298. package/src/components/legacy-reports/tabs/legacy-report-parameters-tab.component.tsx +279 -0
  299. package/src/components/linelist/definition/indicator-to-sql.utils.ts +281 -0
  300. package/src/components/linelist/definition/linelist-definition-editor.component.tsx +1676 -0
  301. package/src/components/linelist/definition/linelist-definition-editor.scss +461 -0
  302. package/src/components/linelist/definition/linelist-definition.types.ts +108 -0
  303. package/src/components/linelist/definition/panels/column-properties-panel.component.tsx +328 -0
  304. package/src/components/linelist/definition/panels/column-selector-panel.component.tsx +1082 -0
  305. package/src/components/linelist/definition/panels/column-selector-panel.scss +100 -0
  306. package/src/components/linelist/definition/panels/custom-sql-column-modal.component.tsx +248 -0
  307. package/src/components/linelist/definition/panels/encounter-diagnosis-column-modal.component.tsx +300 -0
  308. package/src/components/linelist/definition/panels/encounter-diagnosis-column-modal.scss +21 -0
  309. package/src/components/linelist/definition/panels/multi-datasource-selector.component.tsx +332 -0
  310. package/src/components/linelist/definition/panels/multi-datasource-selector.scss +161 -0
  311. package/src/components/linelist/definition/panels/observation-column-modal.component.tsx +450 -0
  312. package/src/components/linelist/definition/panels/observation-column-modal.scss +29 -0
  313. package/src/components/linelist/definition/panels/parameter-panel.component.tsx +659 -0
  314. package/src/components/linelist/definition/panels/parameter-panel.scss +64 -0
  315. package/src/components/linelist/definition/panels/population-source-selector.component.tsx +407 -0
  316. package/src/components/linelist/definition/panels/population-source-selector.scss +187 -0
  317. package/src/components/linelist/design/panels/column-category-selector.component.tsx +433 -0
  318. package/src/components/linelist/design/panels/column-category-selector.scss +329 -0
  319. package/src/components/linelist/design/panels/column-debug-panel.component.tsx +197 -0
  320. package/src/components/linelist/design/panels/column-debug-panel.scss +141 -0
  321. package/src/components/linelist/design/panels/data-catalogue.component.tsx +1062 -0
  322. package/src/components/linelist/design/panels/data-catalogue.scss +263 -0
  323. package/src/components/linelist/design/panels/display-settings-panel.component.tsx +405 -0
  324. package/src/components/linelist/design/panels/display-settings-panel.scss +78 -0
  325. package/src/components/linelist/design/panels/filtermap-editor.component.tsx +434 -0
  326. package/src/components/linelist/design/panels/filtermap-editor.scss +176 -0
  327. package/src/components/linelist/design/panels/json-preview.component.tsx +114 -0
  328. package/src/components/linelist/design/panels/json-preview.scss +85 -0
  329. package/src/components/linelist/design/panels/query-config-panel.component.tsx +1137 -0
  330. package/src/components/linelist/design/panels/query-config-panel.scss +342 -0
  331. package/src/components/linelist/design/panels/sort-config-panel.component.tsx +330 -0
  332. package/src/components/linelist/design/panels/sort-config-panel.scss +77 -0
  333. package/src/components/linelist/design/panels/sql-builder-panel.component.tsx +475 -0
  334. package/src/components/linelist/design/panels/sql-builder-panel.scss +226 -0
  335. package/src/components/linelist/design/panels/transformation-panel.component.tsx +687 -0
  336. package/src/components/linelist/design/panels/transformation-panel.scss +81 -0
  337. package/src/components/linelist/design/panels/visual-filter-panel.component.tsx +595 -0
  338. package/src/components/linelist/design/panels/visual-filter-panel.scss +76 -0
  339. package/src/components/linelist/linelist-dashboard.page.component.tsx +756 -0
  340. package/src/components/linelist/linelist-dashboard.page.scss +240 -0
  341. package/src/components/linelist/linelist-editor.page.component.tsx +134 -0
  342. package/src/components/linelist/linelist-editor.page.scss +28 -0
  343. package/src/components/linelist/linelist-run-report.page.component.tsx +715 -0
  344. package/src/components/linelist/linelist-run-report.page.scss +136 -0
  345. package/src/components/linelist/modals/linelist-report-builder-modal.component.tsx +1454 -0
  346. package/src/components/linelist/modals/linelist-report-builder-modal.scss +164 -0
  347. package/src/components/linelist/modals/preview-parameter-modal.component.tsx +361 -0
  348. package/src/components/report/dashboard/reports-table.component.tsx +186 -0
  349. package/src/components/report/definition/panels/properties-panel.component.tsx +38 -0
  350. package/src/components/report/definition/panels/report-structure-panel.component.tsx +61 -0
  351. package/src/components/report/definition/panels/selection-panel.component.tsx +58 -0
  352. package/src/components/report/definition/report-definition-editor.component.tsx +99 -0
  353. package/src/components/report/definition/report-definition.types.ts +66 -0
  354. package/src/components/report/design/panels/IndicatorPropertiesPanel.scss +33 -0
  355. package/src/components/report/design/panels/IndicatorPropertiesPanel.tsx +389 -0
  356. package/src/components/report/design/panels/JsonPreviewPanel.scss +32 -0
  357. package/src/components/report/design/panels/JsonPreviewPanel.tsx +104 -0
  358. package/src/components/report/design/panels/mapping-preview-panel.component.tsx +82 -0
  359. package/src/components/report/design/panels/mapping-preview-panel.scss +55 -0
  360. package/src/components/report/design/panels/template-structure-panel.component.tsx +296 -0
  361. package/src/components/report/design/panels/template-structure-panel.scss +81 -0
  362. package/src/components/report/design/report-design-editor.component.tsx +1170 -0
  363. package/src/components/report/design/report-design.types.ts +48 -0
  364. package/src/components/report/design/report-design.utils.ts +86 -0
  365. package/src/components/report/panels/report-detail.component.tsx +71 -0
  366. package/src/components/report/panels/report-panel-shell.component.tsx +60 -0
  367. package/src/components/report/report-dashboard.page.component.tsx +554 -0
  368. package/src/components/report/report-editor.page.component.tsx +590 -0
  369. package/src/components/report/report.routes.tsx +32 -0
  370. package/src/components/report-sections/create-report-section-modal.component.tsx +388 -0
  371. package/src/components/report-sections/hooks/useAgeCategories.ts +25 -0
  372. package/src/components/report-sections/hooks/useSectionEditorState.ts +449 -0
  373. package/src/components/report-sections/panels/Dhis2MappingPanel.tsx +157 -0
  374. package/src/components/report-sections/panels/DisaggregationPanel.tsx +97 -0
  375. package/src/components/report-sections/panels/IndicatorPickerPanel.tsx +201 -0
  376. package/src/components/report-sections/panels/SectionBasicsPanel.tsx +27 -0
  377. package/src/components/report-sections/report-section-preview-modal.component.tsx +548 -0
  378. package/src/components/report-sections/report-sections-page.component.tsx +325 -0
  379. package/src/components/report-sections/section-disaggregation.utils.ts +637 -0
  380. package/src/components/report-sections/section-types.ts +55 -0
  381. package/src/components/report-sections/section-utils.ts +50 -0
  382. package/src/components/report-sections/sections-page.scss +79 -0
  383. package/src/components/run-reports/run-reports-page.component.tsx +8 -0
  384. package/src/components/security/access-denied-page.component.tsx +69 -0
  385. package/src/components/security/access-denied-page.scss +39 -0
  386. package/src/components/security/privilege-route.component.test.tsx +79 -0
  387. package/src/components/security/privilege-route.component.tsx +39 -0
  388. package/src/components/shared/compile-setup-modal.component.tsx +182 -0
  389. package/src/components/shared/concept-selector.component.tsx +245 -0
  390. package/src/components/shared/concept-selector.scss +121 -0
  391. package/src/components/shared/header/builder-header-actions.component.tsx +38 -0
  392. package/src/components/shared/header/header.component.tsx +85 -0
  393. package/src/components/shared/header/header.scss +150 -0
  394. package/src/components/shared/header/illustration.component.tsx +34 -0
  395. package/src/components/shared/indicator-properties-panel/IndicatorPropertiesPanel.scss +33 -0
  396. package/src/components/shared/indicator-properties-panel/IndicatorPropertiesPanel.tsx +389 -0
  397. package/src/components/shared/json-preview-panel/JsonPreviewPanel.scss +32 -0
  398. package/src/components/shared/json-preview-panel/JsonPreviewPanel.tsx +104 -0
  399. package/src/components/shared/mapping-preview-panel/mapping-preview-panel.component.tsx +82 -0
  400. package/src/components/shared/mapping-preview-panel/mapping-preview-panel.scss +55 -0
  401. package/src/components/shared/preview/query-results-preview.component.tsx +204 -0
  402. package/src/components/shared/template-structure-panel/template-structure-panel.component.tsx +296 -0
  403. package/src/components/shared/template-structure-panel/template-structure-panel.scss +81 -0
  404. package/src/config-schema.ts +43 -0
  405. package/src/constants/privileges.test.ts +53 -0
  406. package/src/constants/privileges.ts +118 -0
  407. package/src/features/dashboards/DashboardRendererPage.tsx +174 -0
  408. package/src/features/dashboards/DashboardsPage.tsx +164 -0
  409. package/src/features/dashboards/EtlDashboardPage.tsx +32 -0
  410. package/src/features/dashboards/components/DashboardEmptyState.tsx +41 -0
  411. package/src/features/dashboards/components/DashboardGrid.tsx +48 -0
  412. package/src/features/dashboards/components/DashboardHeader.tsx +58 -0
  413. package/src/features/dashboards/components/DashboardSection.tsx +46 -0
  414. package/src/features/dashboards/components/ReportLaunchCard.tsx +51 -0
  415. package/src/features/dashboards/components/WidgetSlotDispatcher.tsx +61 -0
  416. package/src/features/dashboards/components/WidgetUnavailableCard.tsx +36 -0
  417. package/src/features/dashboards/dashboards.scss +196 -0
  418. package/src/features/dashboards/hooks/useDashboard.ts +61 -0
  419. package/src/features/dashboards/hooks/useDashboardWidgets.ts +74 -0
  420. package/src/features/dashboards/hooks/useDashboards.ts +56 -0
  421. package/src/features/dashboards/hooks/useMonitorDataMap.ts +84 -0
  422. package/src/features/dashboards/index.ts +11 -0
  423. package/src/features/dashboards/utils/dashboard-config.util.test.ts +255 -0
  424. package/src/features/dashboards/utils/dashboard-config.util.ts +382 -0
  425. package/src/features/report-visualizer/ReportVisualizerPage.tsx +448 -0
  426. package/src/features/report-visualizer/components/Export/ExportMenu.tsx +141 -0
  427. package/src/features/report-visualizer/components/Export/index.ts +2 -0
  428. package/src/features/report-visualizer/components/ReportExplorer/QuickFilters.tsx +152 -0
  429. package/src/features/report-visualizer/components/ReportExplorer/ReportCategoryFilter.tsx +54 -0
  430. package/src/features/report-visualizer/components/ReportExplorer/ReportExplorerPanel.tsx +201 -0
  431. package/src/features/report-visualizer/components/ReportExplorer/ReportExplorerRail.tsx +202 -0
  432. package/src/features/report-visualizer/components/ReportExplorer/ReportList.tsx +287 -0
  433. package/src/features/report-visualizer/components/ReportExplorer/ReportSearch.tsx +151 -0
  434. package/src/features/report-visualizer/components/ReportExplorer/ReportTagFilter.tsx +100 -0
  435. package/src/features/report-visualizer/components/ReportExplorer/RunReportButton.tsx +42 -0
  436. package/src/features/report-visualizer/components/ReportExplorer/RuntimeParameterForm.tsx +259 -0
  437. package/src/features/report-visualizer/components/ReportExplorer/index.ts +8 -0
  438. package/src/features/report-visualizer/components/ReportWorkspace/ReportLayer.tsx +33 -0
  439. package/src/features/report-visualizer/components/ReportWorkspace/ReportSummary.tsx +88 -0
  440. package/src/features/report-visualizer/components/ReportWorkspace/ReportViewTabs.tsx +72 -0
  441. package/src/features/report-visualizer/components/ReportWorkspace/ReportWorkspaceHeader.tsx +92 -0
  442. package/src/features/report-visualizer/components/ReportWorkspace/ReportWorkspacePanel.tsx +242 -0
  443. package/src/features/report-visualizer/components/ReportWorkspace/index.ts +5 -0
  444. package/src/features/report-visualizer/components/TableView/ColumnVisibilityMenu.tsx +206 -0
  445. package/src/features/report-visualizer/components/TableView/ReportTable.tsx +253 -0
  446. package/src/features/report-visualizer/components/TableView/index.ts +2 -0
  447. package/src/features/report-visualizer/hooks/index.ts +4 -0
  448. package/src/features/report-visualizer/hooks/useExplorerPreferences.ts +103 -0
  449. package/src/features/report-visualizer/hooks/useReportCapabilities.ts +112 -0
  450. package/src/features/report-visualizer/hooks/useReportParameters.ts +152 -0
  451. package/src/features/report-visualizer/hooks/useReports.ts +135 -0
  452. package/src/features/report-visualizer/index.ts +6 -0
  453. package/src/features/report-visualizer/report-visualizer.scss +593 -0
  454. package/src/features/report-visualizer/types/index.ts +1 -0
  455. package/src/features/report-visualizer/types/report-visualizer.types.ts +104 -0
  456. package/src/features/report-visualizer/utils/status-colors.ts +117 -0
  457. package/src/globals.d.ts +14 -0
  458. package/src/hooks/address-template.ts +86 -0
  459. package/src/hooks/concept.ts +112 -0
  460. package/src/hooks/indicator/index.ts +1 -0
  461. package/src/hooks/indicator/useIndicatorsByTheme.ts +41 -0
  462. package/src/hooks/openmrs-reference-data.ts +432 -0
  463. package/src/hooks/theme/index.ts +4 -0
  464. package/src/hooks/theme/useDataTheme.ts +61 -0
  465. package/src/hooks/theme/useDataThemes.ts +28 -0
  466. package/src/hooks/theme/useMambaTableMeta.ts +34 -0
  467. package/src/hooks/theme/useMambaTables.ts +95 -0
  468. package/src/hooks/use-report-builder-privileges.test.tsx +98 -0
  469. package/src/hooks/use-report-builder-privileges.ts +58 -0
  470. package/src/index.ts +29 -0
  471. package/src/resources/address-template/address-template.api.ts +180 -0
  472. package/src/resources/agegroup/agegroups.api.ts +58 -0
  473. package/src/resources/concept/concept.api.ts +116 -0
  474. package/src/resources/concepts/concept-mapper.ts +21 -0
  475. package/src/resources/concepts/concept-types.ts +31 -0
  476. package/src/resources/concepts/concepts.resource.ts +44 -0
  477. package/src/resources/concepts/useConceptSearch.ts +41 -0
  478. package/src/resources/dashboard/dashboard.api.ts +107 -0
  479. package/src/resources/etl-monitor/etl-monitor-test.api.ts +409 -0
  480. package/src/resources/etl-monitor/etl-monitor.api.ts +381 -0
  481. package/src/resources/etl-source/etl-source.api.ts +65 -0
  482. package/src/resources/etl-task/etl-task.api.ts +96 -0
  483. package/src/resources/etl-task/etl-task.types.ts +31 -0
  484. package/src/resources/indicator/indicators.api.ts +125 -0
  485. package/src/resources/legacy-reports/legacy-reports.api.ts +144 -0
  486. package/src/resources/linelist/linelist-reports.api.ts +616 -0
  487. package/src/resources/location/location.api.ts +135 -0
  488. package/src/resources/openmrs-api.ts +40 -0
  489. package/src/resources/patient-identifier-type/patient-identifier-type.api.ts +65 -0
  490. package/src/resources/person-attribute-type/person-attribute-type.api.ts +71 -0
  491. package/src/resources/preview/sql-preview.api.ts +54 -0
  492. package/src/resources/report/reports.api.ts +140 -0
  493. package/src/resources/report-category/report-category.api.ts +41 -0
  494. package/src/resources/report-import-export/import-export-api.ts +164 -0
  495. package/src/resources/report-library/report-library.api.ts +63 -0
  496. package/src/resources/report-section/report-sections.api.ts +73 -0
  497. package/src/resources/report-section/section-preview.api.ts +25 -0
  498. package/src/resources/theme/data-theme.api.ts +88 -0
  499. package/src/resources/theme/etl-schema.api.ts +101 -0
  500. package/src/resources/theme/etl-table-meta.api.ts +45 -0
  501. package/src/root.component.tsx +20 -0
  502. package/src/routes/report-builder.routes.tsx +160 -0
  503. package/src/routes/report-builder.scss +56 -0
  504. package/src/routes.json +28 -0
  505. package/src/sample-template.ts +121 -0
  506. package/src/template-utils.ts +110 -0
  507. package/src/types/carbon-react-inert.d.ts +13 -0
  508. package/src/types/condition-operators.ts +63 -0
  509. package/src/types/dashboard/dashboard.types.ts +137 -0
  510. package/src/types/dashboard/index.ts +4 -0
  511. package/src/types/etl/etl-types.ts +238 -0
  512. package/src/types/etl-monitor/etl-monitor-builder.types.ts +555 -0
  513. package/src/types/etl-monitor/etl-monitor-v2.types.ts +397 -0
  514. package/src/types/etl-monitor/etl-monitor.types.ts +188 -0
  515. package/src/types/etl-monitor/index.ts +6 -0
  516. package/src/types/linelist/compile-config.ts +455 -0
  517. package/src/types/linelist-types.ts +2059 -0
  518. package/src/types/theme/data-theme.types.ts +88 -0
  519. package/src/utils/api-error.utils.test.ts +151 -0
  520. package/src/utils/api-error.utils.ts +131 -0
  521. package/src/utils/config-enhancer.ts +62 -0
  522. package/src/utils/etl-browser/etl-browser.util.test.ts +145 -0
  523. package/src/utils/etl-browser/export-csv.util.ts +43 -0
  524. package/src/utils/etl-browser/group-tables.util.ts +84 -0
  525. package/src/utils/etl-browser/index.ts +4 -0
  526. package/src/utils/etl-browser/summarize-columns.util.ts +27 -0
  527. package/src/utils/etl-browser/table-sql.util.ts +20 -0
  528. package/src/utils/etl-monitor/config-v2-adapter.util.ts +460 -0
  529. package/src/utils/etl-monitor/endpoint-config-normalizer.util.ts +383 -0
  530. package/src/utils/etl-monitor/index.ts +10 -0
  531. package/src/utils/etl-monitor/jsonpath-resolver.util.ts +118 -0
  532. package/src/utils/etl-monitor/normalization-examples.ts +0 -0
  533. package/src/utils/etl-monitor/schema-inspector.util.ts +76 -0
  534. package/src/utils/etl-monitor/semantic-type-detector.util.ts +76 -0
  535. package/src/utils/etl-monitor/status-mapper.util.ts +105 -0
  536. package/src/utils/etl-monitor/value-formatters.util.ts +167 -0
  537. package/src/utils/etl-task/etl-task-card.util.test.ts +239 -0
  538. package/src/utils/etl-task/etl-task-card.util.ts +276 -0
  539. package/src/utils/etl-task/index.ts +1 -0
  540. package/src/utils/html-entities.utils.ts +34 -0
  541. package/src/utils/parameter-resolution.ts +218 -0
  542. package/src/views/etl-monitor-builder/add-monitor-modal.component.scss +0 -0
  543. package/src/views/etl-monitor-builder/add-monitor-modal.component.tsx +210 -0
  544. package/src/views/etl-monitor-builder/etl-monitor-builder.component.scss +157 -0
  545. package/src/views/etl-monitor-builder/etl-monitor-builder.component.tsx +252 -0
  546. package/src/views/etl-monitor-builder/etl-monitor-builder.store.ts +126 -0
  547. package/tools/scss-stub.js +12 -0
  548. package/tools/setup-tests.ts +1 -0
  549. package/translations/en.json +65 -0
  550. package/tsconfig.json +43 -0
  551. package/webpack.config.js +30 -0
@@ -0,0 +1,276 @@
1
+ /**
2
+ * ETL Task card metadata utilities
3
+ *
4
+ * Pure helpers used by the ETL Tasks admin page to derive card metadata
5
+ * (last run, next run, duration) from the OpenMRS task definition and the
6
+ * configured task -> monitor binding.
7
+ *
8
+ * No framework imports — safe to unit test in isolation.
9
+ */
10
+
11
+ import { formatDuration } from '../etl-monitor/value-formatters.util';
12
+ import type { ETLMonitorDto } from '../../types/etl-monitor';
13
+
14
+ const DAY_MS = 86400000;
15
+ const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
16
+
17
+ /**
18
+ * Parse a date leniently. OpenMRS serializes dates with colon-less UTC
19
+ * offsets (e.g. `+0300`) which Safari's `Date` parser rejects; normalize
20
+ * them to `+03:00` before parsing. Returns null for unusable values.
21
+ */
22
+ export function parseLenientDate(value?: string | number | Date | null): Date | null {
23
+ if (value === null || value === undefined || value === '') return null;
24
+ if (value instanceof Date) return isNaN(value.getTime()) ? null : value;
25
+ if (typeof value === 'number') return isNaN(value) ? null : new Date(value);
26
+ if (typeof value !== 'string') return null;
27
+
28
+ const normalized = value.trim().replace(/([+-]\d{2})(\d{2})$/, '$1:$2');
29
+ const date = new Date(normalized);
30
+ return isNaN(date.getTime()) ? null : date;
31
+ }
32
+
33
+ /**
34
+ * Local calendar-day difference between a date and now: 0 = today,
35
+ * -1 = yesterday, etc.
36
+ */
37
+ function calendarDayOffset(date: Date, now: Date): number {
38
+ const startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
39
+ return Math.round((startOfDay(date) - startOfDay(now)) / DAY_MS);
40
+ }
41
+
42
+ /** `Today, 09:12` / `Yesterday, 21:04` / `12 Aug, 09:12` */
43
+ function formatDayTimeLabel(date: Date, now: Date = new Date()): string {
44
+ const hh = String(date.getHours()).padStart(2, '0');
45
+ const mm = String(date.getMinutes()).padStart(2, '0');
46
+ const time = `${hh}:${mm}`;
47
+ const offset = calendarDayOffset(date, now);
48
+ if (offset === 0) return `Today, ${time}`;
49
+ if (offset === -1) return `Yesterday, ${time}`;
50
+ return `${date.getDate()} ${MONTHS[date.getMonth()]}, ${time}`;
51
+ }
52
+
53
+ /**
54
+ * Format a last-run timestamp for the card metadata row.
55
+ */
56
+ export function formatLastRun(value?: string | number | Date | null): string {
57
+ const date = parseLenientDate(value);
58
+ if (!date) return value === null || value === undefined || value === '' ? '—' : String(value);
59
+ return formatDayTimeLabel(date);
60
+ }
61
+
62
+ /**
63
+ * Compute the next run time from the last execution time plus the repeat
64
+ * interval (seconds). Returns null when the task is not repeating or the
65
+ * inputs are unusable. Never clamps to the current time.
66
+ */
67
+ export function computeNextRun(
68
+ lastExecutionTime?: string | number | Date | null,
69
+ repeatIntervalSeconds?: number | null,
70
+ ): Date | null {
71
+ const last = parseLenientDate(lastExecutionTime);
72
+ if (!last) return null;
73
+ if (typeof repeatIntervalSeconds !== 'number' || !isFinite(repeatIntervalSeconds) || repeatIntervalSeconds <= 0) {
74
+ return null;
75
+ }
76
+ return new Date(last.getTime() + repeatIntervalSeconds * 1000);
77
+ }
78
+
79
+ /**
80
+ * Format a computed next-run date for the card metadata row.
81
+ */
82
+ export function formatNextRun(nextRun: Date | null): string {
83
+ return nextRun ? formatDayTimeLabel(nextRun) : 'Not scheduled';
84
+ }
85
+
86
+ /**
87
+ * Format the repeat interval (seconds) for the details view, e.g.
88
+ * `Every 30 min`, `Every 6 h`, `Every 2 d`.
89
+ */
90
+ export function formatRepeatInterval(seconds?: number | null): string {
91
+ if (typeof seconds !== 'number' || !isFinite(seconds) || seconds <= 0) return '—';
92
+ if (seconds < 60) return `Every ${seconds} s`;
93
+ const trim = (n: number) => String(Math.round(n * 10) / 10);
94
+ if (seconds < 3600) return `Every ${trim(seconds / 60)} min`;
95
+ if (seconds < DAY_MS / 1000) return `Every ${trim(seconds / 3600)} h`;
96
+ return `Every ${trim(seconds / 86400)} d`;
97
+ }
98
+
99
+ /**
100
+ * Resolve the ETL monitor referenced by a config value. The value may be a
101
+ * monitor uuid (matched exactly, then case-insensitively) or a monitor code
102
+ * (case-insensitive).
103
+ */
104
+ export function findMonitorByRef(
105
+ monitors: ETLMonitorDto[] | undefined | null,
106
+ ref?: string | null,
107
+ ): ETLMonitorDto | undefined {
108
+ if (!monitors || monitors.length === 0) return undefined;
109
+ if (typeof ref !== 'string' || !ref.trim()) return undefined;
110
+ const value = ref.trim();
111
+
112
+ return (
113
+ monitors.find((m) => m?.uuid === value) ??
114
+ monitors.find((m) => m?.uuid?.toLowerCase() === value.toLowerCase()) ??
115
+ monitors.find((m) => m?.code?.toLowerCase() === value.toLowerCase())
116
+ );
117
+ }
118
+
119
+ export interface ResolvedProgressMonitor {
120
+ /** The raw config value (trimmed) this entry came from */
121
+ ref: string;
122
+ /** The resolved monitor, or undefined when the ref matched nothing */
123
+ monitor?: ETLMonitorDto;
124
+ }
125
+
126
+ /**
127
+ * Resolve the `etlTasks.progressMonitors` config list against the available
128
+ * monitors, in config order. Entries that resolve to the same monitor are
129
+ * deduplicated; unresolved entries are kept so typos stay visible.
130
+ */
131
+ export function resolveProgressMonitors(
132
+ monitors: ETLMonitorDto[] | undefined | null,
133
+ refs?: string[] | null,
134
+ ): ResolvedProgressMonitor[] {
135
+ if (!refs || refs.length === 0) return [];
136
+
137
+ const seenUuids = new Set<string>();
138
+ const resolved: ResolvedProgressMonitor[] = [];
139
+
140
+ for (const ref of refs) {
141
+ if (typeof ref !== 'string' || !ref.trim()) continue;
142
+ const monitor = findMonitorByRef(monitors, ref);
143
+ if (monitor) {
144
+ if (seenUuids.has(monitor.uuid)) continue;
145
+ seenUuids.add(monitor.uuid);
146
+ }
147
+ resolved.push({ ref: ref.trim(), monitor });
148
+ }
149
+
150
+ return resolved;
151
+ }
152
+
153
+ const DURATION_KEY_PATTERN = /duration|elapsed|runtime/i;
154
+ const SECONDS_KEY_PATTERN = /sec/i;
155
+ const MILLISECONDS_KEY_PATTERN = /milli|_ms\b|ms$/i;
156
+ const MAX_SEARCH_DEPTH = 3;
157
+
158
+ /**
159
+ * Normalize a numeric duration to milliseconds using its key as a hint:
160
+ * `*ms*`/`*milli*` keys stay as-is, `*seconds*` keys scale by 1000, and
161
+ * bare values under 1000 are assumed to be seconds (sub-second ETL
162
+ * durations are rare, while bare seconds are common).
163
+ */
164
+ function normalizeDurationMs(value: number, key: string): number {
165
+ if (MILLISECONDS_KEY_PATTERN.test(key)) return value;
166
+ if (SECONDS_KEY_PATTERN.test(key)) return value * 1000;
167
+ return value < 1000 ? value * 1000 : value;
168
+ }
169
+
170
+ function durationFromEntry(key: string, value: unknown): string | null {
171
+ if (value === null || value === undefined || value === '') return null;
172
+ if (typeof value === 'number' && isFinite(value)) {
173
+ return formatDuration(normalizeDurationMs(value, key));
174
+ }
175
+ if (typeof value === 'string') {
176
+ const trimmed = value.trim();
177
+ if (!trimmed) return null;
178
+ const numeric = Number(trimmed);
179
+ if (!isNaN(numeric) && trimmed !== '') {
180
+ return formatDuration(normalizeDurationMs(numeric, key));
181
+ }
182
+ return trimmed;
183
+ }
184
+ return null;
185
+ }
186
+
187
+ /**
188
+ * Search a monitor's raw response for a duration-like value
189
+ * (keys matching /duration|elapsed|runtime/i, bounded depth, cycle-safe).
190
+ * Returns the formatted duration string, or null when nothing usable is found.
191
+ */
192
+ export function extractDurationFromMonitorData(rawResponse: unknown): string | null {
193
+ const visited = new WeakSet<object>();
194
+
195
+ const search = (node: unknown, key: string, depth: number): string | null => {
196
+ if (node === null || node === undefined || depth > MAX_SEARCH_DEPTH) return null;
197
+
198
+ if (DURATION_KEY_PATTERN.test(key)) {
199
+ const result = durationFromEntry(key, node);
200
+ if (result !== null) return result;
201
+ }
202
+
203
+ if (typeof node !== 'object') return null;
204
+ if (visited.has(node as object)) return null;
205
+ visited.add(node as object);
206
+
207
+ const entries = Array.isArray(node)
208
+ ? node.map((item, index) => [String(index), item] as const)
209
+ : Object.entries(node as Record<string, unknown>);
210
+
211
+ for (const [childKey, childValue] of entries) {
212
+ const result = search(childValue, childKey, depth + 1);
213
+ if (result !== null) return result;
214
+ }
215
+ return null;
216
+ };
217
+
218
+ return search(rawResponse, '', 0);
219
+ }
220
+
221
+ const STATUS_KEY_PATTERN = /^(status|state)$/i;
222
+
223
+ /**
224
+ * Count entries in a monitor's raw response whose status matches a pattern.
225
+ * Two shapes are recognized (bounded depth, cycle-safe):
226
+ * - arrays of objects with a `status`/`state` string field, e.g.
227
+ * `{ jobs: [{ status: 'RUNNING' }, { status: 'COMPLETED' }] }`
228
+ * - numeric count fields whose key matches the pattern, e.g. `{ runningCount: 3 }`
229
+ *
230
+ * Returns undefined when nothing matches (no data / unknown), so callers can
231
+ * distinguish "confirmed zero" from "no signal".
232
+ */
233
+ export function countStatusEntries(rawResponse: unknown, valuePattern: RegExp): number | undefined {
234
+ if (rawResponse === null || rawResponse === undefined || typeof rawResponse !== 'object') return undefined;
235
+
236
+ const visited = new WeakSet<object>();
237
+ let found: number | undefined = undefined;
238
+
239
+ const walk = (node: unknown, depth: number): void => {
240
+ if (node === null || node === undefined || depth > MAX_SEARCH_DEPTH) return;
241
+ if (typeof node !== 'object' || visited.has(node as object)) return;
242
+ visited.add(node as object);
243
+
244
+ const entries = Array.isArray(node)
245
+ ? node.map((item) => ['', item] as const)
246
+ : Object.entries(node as Record<string, unknown>);
247
+
248
+ for (const [key, value] of entries) {
249
+ if (typeof value === 'number' && isFinite(value) && valuePattern.test(key)) {
250
+ found = (found ?? 0) + value;
251
+ } else if (STATUS_KEY_PATTERN.test(key) && typeof value === 'string' && valuePattern.test(value)) {
252
+ found = (found ?? 0) + 1;
253
+ } else if (typeof value === 'object' && value !== null) {
254
+ walk(value, depth + 1);
255
+ }
256
+ }
257
+ };
258
+
259
+ walk(rawResponse, 0);
260
+ return found;
261
+ }
262
+
263
+ /**
264
+ * Sum `countStatusEntries` across several monitor raw responses.
265
+ * Returns undefined only when no response yields a signal.
266
+ */
267
+ export function sumStatusCounts(rawResponses: Array<unknown | null | undefined>, valuePattern: RegExp): number | undefined {
268
+ let total: number | undefined = undefined;
269
+ for (const raw of rawResponses) {
270
+ const count = countStatusEntries(raw, valuePattern);
271
+ if (count !== undefined) {
272
+ total = (total ?? 0) + count;
273
+ }
274
+ }
275
+ return total;
276
+ }
@@ -0,0 +1 @@
1
+ export * from './etl-task-card.util';
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Safely decodes common HTML entities that OpenMRS may return
3
+ * after sanitisation (e.g. &lt; &gt; &amp; &quot; &#39;)
4
+ *
5
+ * This is intentionally small and dependency-free.
6
+ */
7
+
8
+ export function decodeHtmlEntities(input?: string | null): string {
9
+ if (!input || typeof input !== 'string') return input ?? '';
10
+
11
+ // Fast exit if nothing looks encoded
12
+ if (!/[&]/.test(input)) return input;
13
+
14
+ // IMPORTANT: Decode &amp; FIRST to handle double-encoded entities like &amp;lt; -> <
15
+
16
+ let decoded = input;
17
+ let prevLength: number;
18
+
19
+ // Apply decoding repeatedly until no more changes (handles double/multiple encoding)
20
+ do {
21
+ prevLength = decoded.length;
22
+ decoded = decoded
23
+ .replace(/&amp;/g, '&') // Must be first to handle double-encoding
24
+ .replace(/&lt;/g, '<')
25
+ .replace(/&gt;/g, '>')
26
+ .replace(/&quot;/g, '"')
27
+ .replace(/&#39;/g, "'")
28
+ .replace(/&#x2F;/g, '/')
29
+ .replace(/&#x60;/g, '`')
30
+ .replace(/&#x3D;/g, '=');
31
+ } while (decoded.length !== prevLength && /[&amp;]/.test(decoded));
32
+
33
+ return decoded;
34
+ }
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Parameter Resolution Utilities
3
+ *
4
+ * Utilities for resolving relative periods to actual dates.
5
+ * Used for date range parameters in reports.
6
+ */
7
+
8
+ import dayjs from 'dayjs';
9
+
10
+ export type RelativePeriod =
11
+ | 'TODAY'
12
+ | 'YESTERDAY'
13
+ | 'THIS_WEEK'
14
+ | 'LAST_WEEK'
15
+ | 'THIS_MONTH'
16
+ | 'LAST_MONTH'
17
+ | 'THIS_QUARTER'
18
+ | 'LAST_QUARTER'
19
+ | 'THIS_YEAR'
20
+ | 'LAST_YEAR'
21
+ | 'LAST_7_DAYS'
22
+ | 'LAST_30_DAYS'
23
+ | 'LAST_90_DAYS';
24
+
25
+ /**
26
+ * Relative period options for UI dropdown
27
+ */
28
+ export const RELATIVE_PERIOD_OPTIONS: Array<{ value: RelativePeriod; label: string }> = [
29
+ { value: 'TODAY', label: 'Today' },
30
+ { value: 'YESTERDAY', label: 'Yesterday' },
31
+ { value: 'THIS_WEEK', label: 'This Week' },
32
+ { value: 'LAST_WEEK', label: 'Last Week' },
33
+ { value: 'THIS_MONTH', label: 'This Month' },
34
+ { value: 'LAST_MONTH', label: 'Last Month' },
35
+ { value: 'THIS_QUARTER', label: 'This Quarter' },
36
+ { value: 'LAST_QUARTER', label: 'Last Quarter' },
37
+ { value: 'THIS_YEAR', label: 'This Year' },
38
+ { value: 'LAST_YEAR', label: 'Last Year' },
39
+ { value: 'LAST_7_DAYS', label: 'Last 7 Days' },
40
+ { value: 'LAST_30_DAYS', label: 'Last 30 Days' },
41
+ { value: 'LAST_90_DAYS', label: 'Last 90 Days' },
42
+ ];
43
+
44
+ /**
45
+ * Resolves a relative period to a date range
46
+ * @param period - The relative period identifier
47
+ * @returns Object with start and end dates
48
+ */
49
+ export function resolveRelativePeriod(period: RelativePeriod): { start: Date; end: Date } {
50
+ const now = new Date();
51
+
52
+ switch (period) {
53
+ case 'TODAY':
54
+ return { start: now, end: now };
55
+
56
+ case 'YESTERDAY': {
57
+ const yesterday = new Date(now);
58
+ yesterday.setDate(now.getDate() - 1);
59
+ return { start: yesterday, end: yesterday };
60
+ }
61
+
62
+ case 'THIS_WEEK': {
63
+ const weekStart = new Date(now);
64
+ weekStart.setDate(now.getDate() - now.getDay());
65
+ const weekEnd = new Date(now);
66
+ weekEnd.setDate(now.getDate() + (6 - now.getDay()));
67
+ return { start: weekStart, end: weekEnd };
68
+ }
69
+
70
+ case 'LAST_WEEK': {
71
+ const lastWeekStart = new Date(now);
72
+ lastWeekStart.setDate(now.getDate() - now.getDay() - 7);
73
+ const lastWeekEnd = new Date(now);
74
+ lastWeekEnd.setDate(now.getDate() - now.getDay() - 1);
75
+ return { start: lastWeekStart, end: lastWeekEnd };
76
+ }
77
+
78
+ case 'THIS_MONTH': {
79
+ return {
80
+ start: new Date(now.getFullYear(), now.getMonth(), 1),
81
+ end: new Date(now.getFullYear(), now.getMonth() + 1, 0),
82
+ };
83
+ }
84
+
85
+ case 'LAST_MONTH': {
86
+ return {
87
+ start: new Date(now.getFullYear(), now.getMonth() - 1, 1),
88
+ end: new Date(now.getFullYear(), now.getMonth(), 0),
89
+ };
90
+ }
91
+
92
+ case 'THIS_QUARTER': {
93
+ const quarter = Math.floor(now.getMonth() / 3);
94
+ return {
95
+ start: new Date(now.getFullYear(), quarter * 3, 1),
96
+ end: new Date(now.getFullYear(), (quarter + 1) * 3, 0),
97
+ };
98
+ }
99
+
100
+ case 'LAST_QUARTER': {
101
+ const currentQuarter = Math.floor(now.getMonth() / 3);
102
+ if (currentQuarter === 0) {
103
+ return {
104
+ start: new Date(now.getFullYear() - 1, 9, 1),
105
+ end: new Date(now.getFullYear() - 1, 12, 0),
106
+ };
107
+ }
108
+ return {
109
+ start: new Date(now.getFullYear(), (currentQuarter - 1) * 3, 1),
110
+ end: new Date(now.getFullYear(), currentQuarter * 3, 0),
111
+ };
112
+ }
113
+
114
+ case 'THIS_YEAR': {
115
+ return {
116
+ start: new Date(now.getFullYear(), 0, 1),
117
+ end: new Date(now.getFullYear(), 12, 0),
118
+ };
119
+ }
120
+
121
+ case 'LAST_YEAR': {
122
+ return {
123
+ start: new Date(now.getFullYear() - 1, 0, 1),
124
+ end: new Date(now.getFullYear() - 1, 12, 0),
125
+ };
126
+ }
127
+
128
+ case 'LAST_7_DAYS': {
129
+ const sevenDaysAgo = new Date(now);
130
+ sevenDaysAgo.setDate(now.getDate() - 7);
131
+ return { start: sevenDaysAgo, end: now };
132
+ }
133
+
134
+ case 'LAST_30_DAYS': {
135
+ const thirtyDaysAgo = new Date(now);
136
+ thirtyDaysAgo.setDate(now.getDate() - 30);
137
+ return { start: thirtyDaysAgo, end: now };
138
+ }
139
+
140
+ case 'LAST_90_DAYS': {
141
+ const ninetyDaysAgo = new Date(now);
142
+ ninetyDaysAgo.setDate(now.getDate() - 90);
143
+ return { start: ninetyDaysAgo, end: now };
144
+ }
145
+
146
+ default:
147
+ throw new Error(`Unknown relative period: ${period}`);
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Formats a date as YYYY-MM-DD
153
+ */
154
+ export function formatDate(date: Date): string {
155
+ return dayjs(date).format('YYYY-MM-DD');
156
+ }
157
+
158
+ /**
159
+ * Formats a date as DD/MM/YYYY for display
160
+ */
161
+ export function formatDisplayDate(date: Date): string {
162
+ return dayjs(date).format('DD/MM/YYYY');
163
+ }
164
+
165
+ /**
166
+ * Parses a date string in YYYY-MM-DD format to Date object
167
+ */
168
+ export function parseDate(dateString: string): Date | null {
169
+ const parsed = dayjs(dateString, 'YYYY-MM-DD', true);
170
+ return parsed.isValid() ? parsed.toDate() : null;
171
+ }
172
+
173
+ /**
174
+ * Validates if a string is a valid date in YYYY-MM-DD format
175
+ */
176
+ export function isValidDate(dateString: string): boolean {
177
+ return dayjs(dateString, 'YYYY-MM-DD', true).isValid();
178
+ }
179
+
180
+ /**
181
+ * Gets a display label for a relative period
182
+ */
183
+ export function getRelativePeriodLabel(period: RelativePeriod): string {
184
+ const option = RELATIVE_PERIOD_OPTIONS.find(opt => opt.value === period);
185
+ return option?.label || period;
186
+ }
187
+
188
+ /**
189
+ * Resolves a parameter value to an actual date string
190
+ * Handles both FIXED and RELATIVE modes
191
+ */
192
+ export function resolveParameterValue(
193
+ value: { mode: 'FIXED' | 'RELATIVE'; fixedDate?: string; relativePeriod?: RelativePeriod }
194
+ ): string {
195
+ if (!value) {
196
+ return formatDate(new Date());
197
+ }
198
+
199
+ if (value.mode === 'FIXED' && value.fixedDate) {
200
+ return value.fixedDate;
201
+ }
202
+
203
+ if (value.mode === 'RELATIVE' && value.relativePeriod) {
204
+ const { start } = resolveRelativePeriod(value.relativePeriod);
205
+ return formatDate(start);
206
+ }
207
+
208
+ return formatDate(new Date());
209
+ }
210
+
211
+ /**
212
+ * Type guard to check if a value is a date parameter value
213
+ */
214
+ export function isDateParameterValue(
215
+ value: any
216
+ ): value is { mode: 'FIXED' | 'RELATIVE'; fixedDate?: string; relativePeriod?: RelativePeriod } {
217
+ return value && typeof value === 'object' && 'mode' in value;
218
+ }