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

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 (670) 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/128.css +1 -0
  9. package/dist/128.css.map +1 -0
  10. package/dist/128.js +338 -0
  11. package/dist/128.js.map +1 -0
  12. package/dist/1480.js +1 -0
  13. package/dist/1480.js.map +1 -0
  14. package/dist/1646.js +1 -0
  15. package/dist/1646.js.map +1 -0
  16. package/dist/1869.js +1 -0
  17. package/dist/1869.js.map +1 -0
  18. package/dist/1877.js +1 -0
  19. package/dist/1877.js.map +1 -0
  20. package/dist/2131.js +1 -0
  21. package/dist/2131.js.map +1 -0
  22. package/dist/2317.js +1 -0
  23. package/dist/2317.js.map +1 -0
  24. package/dist/2408.js +1 -0
  25. package/dist/2408.js.map +1 -0
  26. package/dist/2416.js +1 -0
  27. package/dist/2416.js.map +1 -0
  28. package/dist/282.js +1 -0
  29. package/dist/282.js.map +1 -0
  30. package/dist/2881.js +1 -0
  31. package/dist/2881.js.map +1 -0
  32. package/dist/2997.js +1 -0
  33. package/dist/2997.js.map +1 -0
  34. package/dist/3378.js +1 -0
  35. package/dist/3378.js.map +1 -0
  36. package/dist/3963.js +1 -0
  37. package/dist/3963.js.map +1 -0
  38. package/dist/4106.js +1 -0
  39. package/dist/4106.js.map +1 -0
  40. package/dist/4111.js +1 -0
  41. package/dist/4111.js.map +1 -0
  42. package/dist/4171.css +1 -0
  43. package/dist/4171.css.map +1 -0
  44. package/dist/4171.js +43 -0
  45. package/dist/4171.js.map +1 -0
  46. package/dist/434.js +1 -0
  47. package/dist/434.js.map +1 -0
  48. package/dist/4348.js +1 -0
  49. package/dist/4348.js.map +1 -0
  50. package/dist/4383.js +1 -0
  51. package/dist/4383.js.map +1 -0
  52. package/dist/4658.js +1 -0
  53. package/dist/4658.js.map +1 -0
  54. package/dist/4668.js +1 -0
  55. package/dist/4668.js.map +1 -0
  56. package/dist/4928.js +1 -0
  57. package/dist/4928.js.map +1 -0
  58. package/dist/5098.js +1 -0
  59. package/dist/5098.js.map +1 -0
  60. package/dist/5117.js +1 -0
  61. package/dist/5117.js.map +1 -0
  62. package/dist/5132.js +1 -0
  63. package/dist/5132.js.map +1 -0
  64. package/dist/5145.js +1 -0
  65. package/dist/5145.js.map +1 -0
  66. package/dist/550.js +1 -0
  67. package/dist/550.js.map +1 -0
  68. package/dist/5503.js +1 -0
  69. package/dist/5503.js.map +1 -0
  70. package/dist/556.js +1 -0
  71. package/dist/556.js.map +1 -0
  72. package/dist/5644.js +1 -0
  73. package/dist/5644.js.map +1 -0
  74. package/dist/5940.js +1 -0
  75. package/dist/5940.js.map +1 -0
  76. package/dist/6047.js +1 -0
  77. package/dist/6047.js.map +1 -0
  78. package/dist/6237.js +1 -0
  79. package/dist/6237.js.map +1 -0
  80. package/dist/6371.js +1 -0
  81. package/dist/6371.js.map +1 -0
  82. package/dist/6377.js +1 -0
  83. package/dist/6377.js.map +1 -0
  84. package/dist/6444.js +1 -0
  85. package/dist/6444.js.map +1 -0
  86. package/dist/6508.js +1 -0
  87. package/dist/6508.js.map +1 -0
  88. package/dist/6652.js +1 -0
  89. package/dist/6652.js.map +1 -0
  90. package/dist/6686.js +1 -0
  91. package/dist/6686.js.map +1 -0
  92. package/dist/6724.js +1 -0
  93. package/dist/6724.js.map +1 -0
  94. package/dist/6867.js +19 -0
  95. package/dist/6867.js.map +1 -0
  96. package/dist/6904.js +1 -0
  97. package/dist/6904.js.map +1 -0
  98. package/dist/7045.js +1 -0
  99. package/dist/7045.js.map +1 -0
  100. package/dist/7175.js +1 -0
  101. package/dist/7175.js.map +1 -0
  102. package/dist/7182.js +1 -0
  103. package/dist/7182.js.map +1 -0
  104. package/dist/7475.js +1 -0
  105. package/dist/7475.js.map +1 -0
  106. package/dist/7742.js +1 -0
  107. package/dist/7742.js.map +1 -0
  108. package/dist/7912.js +1 -0
  109. package/dist/7912.js.map +1 -0
  110. package/dist/8251.js +1 -0
  111. package/dist/8251.js.map +1 -0
  112. package/dist/8358.js +1 -0
  113. package/dist/8358.js.map +1 -0
  114. package/dist/8359.js +1 -0
  115. package/dist/8359.js.map +1 -0
  116. package/dist/8695.js +1 -0
  117. package/dist/8695.js.map +1 -0
  118. package/dist/903.js +1 -0
  119. package/dist/903.js.map +1 -0
  120. package/dist/9072.js +1 -0
  121. package/dist/9072.js.map +1 -0
  122. package/dist/9806.js +1 -0
  123. package/dist/9806.js.map +1 -0
  124. package/dist/997.js +1 -0
  125. package/dist/997.js.map +1 -0
  126. package/dist/openmrs-esm-report-builder.js +3 -0
  127. package/dist/openmrs-esm-report-builder.js.buildmanifest.json +1433 -0
  128. package/dist/openmrs-esm-report-builder.js.map +1 -0
  129. package/dist/routes.json +1 -0
  130. package/e2e/core/env.ts +5 -0
  131. package/e2e/core/global-setup.ts +34 -0
  132. package/e2e/core/test.ts +21 -0
  133. package/e2e/pages/app-shell.page.ts +35 -0
  134. package/e2e/pages/etl-sources.page.ts +36 -0
  135. package/e2e/pages/report-sections.page.ts +21 -0
  136. package/e2e/pages/section-preview.modal.ts +29 -0
  137. package/e2e/specs/etl-sources.spec.ts +51 -0
  138. package/e2e/specs/navigation.spec.ts +13 -0
  139. package/e2e/specs/section-preview-validation.spec.ts +38 -0
  140. package/e2e/specs/section-preview.spec.ts +94 -0
  141. package/e2e/support/github/Dockerfile +32 -0
  142. package/e2e/support/github/Dockerfile.dockerignore +13 -0
  143. package/e2e/support/github/docker-compose.yml +31 -0
  144. package/e2e/support/github/run-e2e-docker-env.sh +131 -0
  145. package/e2e/support/github/spa-assemble-config.json +6 -0
  146. package/e2e/tsconfig.json +11 -0
  147. package/example.env +5 -0
  148. package/linelist_report_builder_design_spec.md +816 -0
  149. package/package.json +98 -0
  150. package/playwright.config.ts +28 -0
  151. package/rspack.config.js +2 -0
  152. package/src/__debug__/all-designs.test.tsx +33 -0
  153. package/src/admin-card-link.extension.module.scss +55 -0
  154. package/src/admin-card-link.extension.tsx +24 -0
  155. package/src/components/admin/admin-page.component.tsx +75 -0
  156. package/src/components/admin/age-categories-page.component.tsx +109 -0
  157. package/src/components/admin/age-groups-page.component.tsx +146 -0
  158. package/src/components/admin/etl-browser/columns-tab.component.tsx +80 -0
  159. package/src/components/admin/etl-browser/etl-browser-page.component.tsx +309 -0
  160. package/src/components/admin/etl-browser/etl-browser.component.scss +424 -0
  161. package/src/components/admin/etl-browser/metadata-tab.component.tsx +65 -0
  162. package/src/components/admin/etl-browser/preview-grid.component.tsx +189 -0
  163. package/src/components/admin/etl-browser/relationships-tab.component.tsx +21 -0
  164. package/src/components/admin/etl-browser/sources-tree.component.tsx +118 -0
  165. package/src/components/admin/etl-browser/table-detail.component.tsx +124 -0
  166. package/src/components/admin/etl-browser/table-info-strip.component.tsx +51 -0
  167. package/src/components/admin/etl-browser/table-list.component.tsx +136 -0
  168. package/src/components/admin/etl-browser/use-table-preview.ts +47 -0
  169. package/src/components/admin/etl-sources-page.component.tsx +355 -0
  170. package/src/components/admin/etl-tasks-page.component.scss +370 -0
  171. package/src/components/admin/etl-tasks-page.component.tsx +768 -0
  172. package/src/components/admin/report-categories-page.component.tsx +267 -0
  173. package/src/components/admin/report-library-page.component.tsx +551 -0
  174. package/src/components/ai-support/ai-assist-button.component.tsx +30 -0
  175. package/src/components/ai-support/ai-assist-modal.component.tsx +81 -0
  176. package/src/components/ai-support/ai.service.ts +21 -0
  177. package/src/components/ai-support/ai.types.ts +12 -0
  178. package/src/components/app-shell/report-builder-shell.component.tsx +242 -0
  179. package/src/components/app-shell/report-builder-shell.scss +18 -0
  180. package/src/components/dashboards/dashboard-config.schema.ts +97 -0
  181. package/src/components/dashboards/dashboard-form-modal.component.tsx +150 -0
  182. package/src/components/dashboards/dashboards-admin.scss +62 -0
  183. package/src/components/dashboards/dashboards-page.component.tsx +153 -0
  184. package/src/components/dashboards/dashboards-table.component.tsx +130 -0
  185. package/src/components/dashboards/sections/dashboard-autoinclude.section.tsx +75 -0
  186. package/src/components/dashboards/sections/dashboard-basics.section.tsx +80 -0
  187. package/src/components/dashboards/sections/dashboard-json.section.tsx +79 -0
  188. package/src/components/dashboards/sections/dashboard-sections-editor.section.tsx +130 -0
  189. package/src/components/dashboards/sections/dashboard-widgets-editor.section.tsx +184 -0
  190. package/src/components/data-themes/data-theme-form.component.tsx +59 -0
  191. package/src/components/data-themes/data-theme-modal.component.tsx +349 -0
  192. package/src/components/data-themes/data-themes-page.component.tsx +139 -0
  193. package/src/components/data-themes/data-themes-table.component.tsx +98 -0
  194. package/src/components/data-themes/icon-registry.ts +35 -0
  195. package/src/components/data-themes/sections/data-theme-basics.section.tsx +63 -0
  196. package/src/components/data-themes/sections/data-theme-condition-columns.section.tsx +397 -0
  197. package/src/components/data-themes/sections/data-theme-fields-editor.section.tsx +125 -0
  198. package/src/components/data-themes/sections/data-theme-metadata.section.tsx +245 -0
  199. package/src/components/data-themes/sections/data-theme-preview.section.tsx +115 -0
  200. package/src/components/data-themes/sections/data-theme-source.section.tsx +184 -0
  201. package/src/components/data-visualizer/components/cqi-components/cqi-data-table.component.tsx +214 -0
  202. package/src/components/data-visualizer/components/cqi-components/cqi-elements.ts +203 -0
  203. package/src/components/data-visualizer/components/cqi-components/detail.component.tsx +110 -0
  204. package/src/components/data-visualizer/components/cqi-components/detail.scss +22 -0
  205. package/src/components/data-visualizer/components/data-table/data-table.component.tsx +208 -0
  206. package/src/components/data-visualizer/components/data-table/data-tables.scss +206 -0
  207. package/src/components/data-visualizer/components/empty-state/empty-state-illustration.component.tsx +53 -0
  208. package/src/components/data-visualizer/components/header/header.component.tsx +43 -0
  209. package/src/components/data-visualizer/components/header/header.scss +71 -0
  210. package/src/components/data-visualizer/components/model/confirm.component.tsx +40 -0
  211. package/src/components/data-visualizer/components/panel/panel.component.tsx +20 -0
  212. package/src/components/data-visualizer/components/panel/panel.scss +25 -0
  213. package/src/components/data-visualizer/components/popover/modifier-panel.tsx +53 -0
  214. package/src/components/data-visualizer/constants.ts +445 -0
  215. package/src/components/data-visualizer/data-visualizer-illustration.component.tsx +31 -0
  216. package/src/components/data-visualizer/data-visualizer.component.tsx +1935 -0
  217. package/src/components/data-visualizer/data-visualizer.resource.ts +462 -0
  218. package/src/components/data-visualizer/data-visualizer.scss +448 -0
  219. package/src/components/data-visualizer/declarations.d.ts +131 -0
  220. package/src/components/data-visualizer/parameter-inputs/boolean-parameter-input.component.tsx +34 -0
  221. package/src/components/data-visualizer/parameter-inputs/concept-parameter-input.component.tsx +81 -0
  222. package/src/components/data-visualizer/parameter-inputs/date-parameter-input.component.tsx +110 -0
  223. package/src/components/data-visualizer/parameter-inputs/date-range-input.component.scss +47 -0
  224. package/src/components/data-visualizer/parameter-inputs/date-range-input.component.tsx +228 -0
  225. package/src/components/data-visualizer/parameter-inputs/identifier-type-parameter-input.component.tsx +69 -0
  226. package/src/components/data-visualizer/parameter-inputs/list-parameter-input.component.tsx +73 -0
  227. package/src/components/data-visualizer/parameter-inputs/location-parameter-input.component.tsx +81 -0
  228. package/src/components/data-visualizer/parameter-inputs/number-parameter-input.component.tsx +40 -0
  229. package/src/components/data-visualizer/parameter-inputs/person-attribute-parameter-input.component.tsx +71 -0
  230. package/src/components/data-visualizer/parameter-inputs/text-parameter-input.component.tsx +52 -0
  231. package/src/components/data-visualizer/report-parameter-modal.component.tsx +383 -0
  232. package/src/components/data-visualizer/types.ts +206 -0
  233. package/src/components/etl-monitor/builder/builder-state-machine.ts +381 -0
  234. package/src/components/etl-monitor/builder/design-registry.tsx +139 -0
  235. package/src/components/etl-monitor/builder/etl-monitor-builder-context.tsx +702 -0
  236. package/src/components/etl-monitor/builder/etl-monitor-builder-modal.component.tsx +461 -0
  237. package/src/components/etl-monitor/builder/etl-monitor-builder-modal.scss +256 -0
  238. package/src/components/etl-monitor/builder/etl-monitor-builder-page.component.tsx +387 -0
  239. package/src/components/etl-monitor/builder/etl-monitor-builder-page.scss +976 -0
  240. package/src/components/etl-monitor/builder/generated-config-panel.component.tsx +168 -0
  241. package/src/components/etl-monitor/builder/generated-config-panel.scss +198 -0
  242. package/src/components/etl-monitor/builder/index.ts +5 -0
  243. package/src/components/etl-monitor/builder/monitor-preview.tsx +124 -0
  244. package/src/components/etl-monitor/builder/steps/data-source-step.component.tsx +667 -0
  245. package/src/components/etl-monitor/builder/steps/data-source-step.scss +284 -0
  246. package/src/components/etl-monitor/builder/steps/design-samples.ts +278 -0
  247. package/src/components/etl-monitor/builder/steps/design-step.component.tsx +299 -0
  248. package/src/components/etl-monitor/builder/steps/design-step.scss +479 -0
  249. package/src/components/etl-monitor/builder/steps/fields-step.component.tsx +859 -0
  250. package/src/components/etl-monitor/builder/steps/fields-step.scss +459 -0
  251. package/src/components/etl-monitor/builder/steps/general-step.component.tsx +288 -0
  252. package/src/components/etl-monitor/builder/steps/general-step.scss +103 -0
  253. package/src/components/etl-monitor/builder/steps/index.ts +5 -0
  254. package/src/components/etl-monitor/builder/steps/preview-step.component.tsx +245 -0
  255. package/src/components/etl-monitor/builder/steps/preview-step.scss +236 -0
  256. package/src/components/etl-monitor/etl-monitor-card-shell.component.tsx +154 -0
  257. package/src/components/etl-monitor/etl-monitor-card-shell.scss +103 -0
  258. package/src/components/etl-monitor/etl-monitor-dashboard.component.tsx +227 -0
  259. package/src/components/etl-monitor/etl-monitor-dashboard.scss +148 -0
  260. package/src/components/etl-monitor/etl-monitor-status-card.component.tsx +192 -0
  261. package/src/components/etl-monitor/etl-monitors-page.component.tsx +621 -0
  262. package/src/components/etl-monitor/renderers/DetailsRenderer.tsx +2 -0
  263. package/src/components/etl-monitor/renderers/ErrorLogRenderer.tsx +2 -0
  264. package/src/components/etl-monitor/renderers/EtlMonitorWidget.tsx +97 -0
  265. package/src/components/etl-monitor/renderers/MetricsGridRenderer.tsx +2 -0
  266. package/src/components/etl-monitor/renderers/MonitorRenderer.tsx +175 -0
  267. package/src/components/etl-monitor/renderers/ProgressRenderer.tsx +2 -0
  268. package/src/components/etl-monitor/renderers/StatusCardRenderer.tsx +2 -0
  269. package/src/components/etl-monitor/renderers/SummaryCardRenderer.tsx +2 -0
  270. package/src/components/etl-monitor/renderers/TableRenderer.tsx +2 -0
  271. package/src/components/etl-monitor/renderers/component-icons.tsx +33 -0
  272. package/src/components/etl-monitor/renderers/components/details-renderer.tsx +195 -0
  273. package/src/components/etl-monitor/renderers/components/error-log-renderer.tsx +104 -0
  274. package/src/components/etl-monitor/renderers/components/index.ts +6 -0
  275. package/src/components/etl-monitor/renderers/components/log-renderer.tsx +86 -0
  276. package/src/components/etl-monitor/renderers/components/metrics-grid-renderer.tsx +133 -0
  277. package/src/components/etl-monitor/renderers/components/progress-renderer.tsx +188 -0
  278. package/src/components/etl-monitor/renderers/components/status-card-renderer.tsx +247 -0
  279. package/src/components/etl-monitor/renderers/components/summary-card-renderer.tsx +160 -0
  280. package/src/components/etl-monitor/renderers/components/table-renderer.tsx +175 -0
  281. package/src/components/etl-monitor/renderers/components/time-series-renderer.tsx +310 -0
  282. package/src/components/etl-monitor/renderers/data-transformer.ts +361 -0
  283. package/src/components/etl-monitor/renderers/index.ts +11 -0
  284. package/src/components/etl-monitor/renderers/legacy-monitor-renderer.tsx +69 -0
  285. package/src/components/etl-monitor/renderers/monitor-renderer.tsx +6 -0
  286. package/src/components/etl-monitor/renderers/monitor-renderers.scss +1621 -0
  287. package/src/components/etl-monitor/renderers/monitor-widget-card.component.tsx +54 -0
  288. package/src/components/etl-monitor/renderers/monitor-widget-card.scss +16 -0
  289. package/src/components/etl-monitor/renderers/v2-monitor-renderer.tsx +227 -0
  290. package/src/components/import-export/artifact-groups.ts +153 -0
  291. package/src/components/import-export/export-report-modal.component.tsx +265 -0
  292. package/src/components/import-export/import-export-page.component.tsx +610 -0
  293. package/src/components/import-export/import-export.styles.scss +825 -0
  294. package/src/components/import-export/import-package-modal.component.tsx +401 -0
  295. package/src/components/import-export/index.ts +3 -0
  296. package/src/components/indicators/README.md +24 -0
  297. package/src/components/indicators/base-indicator-basic-fields.component.tsx +18 -0
  298. package/src/components/indicators/base-indicator-basics.section.tsx +54 -0
  299. package/src/components/indicators/base-indicator-countby.section.tsx +25 -0
  300. package/src/components/indicators/base-indicator-criteria.section.tsx +83 -0
  301. package/src/components/indicators/base-indicator-details-form.component.tsx +80 -0
  302. package/src/components/indicators/base-indicator-theme-unit-fields.component.tsx +39 -0
  303. package/src/components/indicators/create-base-indicator-modal.component.tsx +623 -0
  304. package/src/components/indicators/create-composite-base-indicator-modal.component.tsx +295 -0
  305. package/src/components/indicators/create-custom-indicator-modal.component.tsx +548 -0
  306. package/src/components/indicators/create-final-indicator-modal.component.tsx +285 -0
  307. package/src/components/indicators/custom-condition-input.component.tsx +310 -0
  308. package/src/components/indicators/diagnosis-filters-form.component.tsx +101 -0
  309. package/src/components/indicators/disaggregation-panel.component.tsx +93 -0
  310. package/src/components/indicators/handler/concept-search-multiselect.component.tsx +153 -0
  311. package/src/components/indicators/handler/question-answer-concept-search.component.tsx +336 -0
  312. package/src/components/indicators/indicator-run-preview-modal.component.tsx +391 -0
  313. package/src/components/indicators/indicator-search-select.component.tsx +297 -0
  314. package/src/components/indicators/indicator-status-tag.component.tsx +9 -0
  315. package/src/components/indicators/indicators-page.component.tsx +673 -0
  316. package/src/components/indicators/indicators-page.scss +121 -0
  317. package/src/components/indicators/indicators-table.component.tsx +188 -0
  318. package/src/components/indicators/preview-table.component.tsx +31 -0
  319. package/src/components/indicators/sections/composite-indicator-basics.section.tsx +36 -0
  320. package/src/components/indicators/sections/composite-indicator-picker.section.tsx +116 -0
  321. package/src/components/indicators/sections/composite-indicator-sql-preview.section.tsx +31 -0
  322. package/src/components/indicators/sections/custom-indicator-basics.section.tsx +65 -0
  323. package/src/components/indicators/sections/custom-indicator-disaggregation.section.tsx +93 -0
  324. package/src/components/indicators/sections/custom-indicator-filters.section.tsx +203 -0
  325. package/src/components/indicators/sections/custom-indicator-population.section.tsx +107 -0
  326. package/src/components/indicators/sections/custom-indicator-sql-preview.section.tsx +108 -0
  327. package/src/components/indicators/sections/final-indicator-basics.section.tsx +46 -0
  328. package/src/components/indicators/sections/final-indicator-disaggregation.section.tsx +47 -0
  329. package/src/components/indicators/sections/final-indicator-picker.section.tsx +60 -0
  330. package/src/components/indicators/sections/final-indicator-preview.section.tsx +20 -0
  331. package/src/components/indicators/sections/final-indicator-results-preview.section.tsx +65 -0
  332. package/src/components/indicators/sections/indicator-basics.section.tsx +40 -0
  333. package/src/components/indicators/sections/indicator-conditions.section.tsx +279 -0
  334. package/src/components/indicators/sections/indicator-sql-preview.section.tsx +63 -0
  335. package/src/components/indicators/sections/indicator-theme.section.tsx +48 -0
  336. package/src/components/indicators/sql-preview.component.tsx +19 -0
  337. package/src/components/indicators/tag-input.component.tsx +177 -0
  338. package/src/components/indicators/types/base-indicator-form.types.ts +17 -0
  339. package/src/components/indicators/types/base-indicator-theme.constants.ts +8 -0
  340. package/src/components/indicators/types/composite-indicator.types.ts +27 -0
  341. package/src/components/indicators/types/condition-ui.types.ts +11 -0
  342. package/src/components/indicators/types/custom-indicator.types.ts +161 -0
  343. package/src/components/indicators/types/data-theme-config.types.ts +88 -0
  344. package/src/components/indicators/types/indicator-types.ts +57 -0
  345. package/src/components/indicators/types/sql-builders.ts +43 -0
  346. package/src/components/indicators/utils/composite-indicator-sql.utils.test.ts +143 -0
  347. package/src/components/indicators/utils/composite-indicator-sql.utils.ts +426 -0
  348. package/src/components/indicators/utils/concept-preload.utils.ts +21 -0
  349. package/src/components/indicators/utils/custom-indicator-interpreter.test.ts +493 -0
  350. package/src/components/indicators/utils/custom-indicator-interpreter.ts +702 -0
  351. package/src/components/indicators/utils/final-indicator-sql.utils.ts +190 -0
  352. package/src/components/indicators/utils/indicator-conditions-hydration.utils.ts +254 -0
  353. package/src/components/indicators/utils/indicator-sql-resolution.utils.ts +204 -0
  354. package/src/components/indicators/utils/indicator-sql.utils.ts +721 -0
  355. package/src/components/indicators/utils/population-sql.compiler.test.ts +985 -0
  356. package/src/components/indicators/utils/population-sql.compiler.ts +858 -0
  357. package/src/components/landing/landing-action-item.component.tsx +50 -0
  358. package/src/components/landing/landing-action-list.component.tsx +12 -0
  359. package/src/components/landing/landing-activity-list.component.tsx +47 -0
  360. package/src/components/landing/landing-footer-grid.component.tsx +45 -0
  361. package/src/components/landing/landing-hero.component.tsx +18 -0
  362. package/src/components/landing/landing-section-card.component.tsx +33 -0
  363. package/src/components/landing/report-builder-landing-page.component.tsx +186 -0
  364. package/src/components/landing/report-builder-landing-page.scss +131 -0
  365. package/src/components/legacy-reports/legacy-report-detail-page.component.tsx +300 -0
  366. package/src/components/legacy-reports/legacy-report-editor-page.component.tsx +324 -0
  367. package/src/components/legacy-reports/legacy-report-upload-modal.component.tsx +307 -0
  368. package/src/components/legacy-reports/legacy-reports-page.component.tsx +206 -0
  369. package/src/components/legacy-reports/legacy-reports-table.component.tsx +154 -0
  370. package/src/components/legacy-reports/tabs/legacy-report-datasets-tab.component.tsx +344 -0
  371. package/src/components/legacy-reports/tabs/legacy-report-dimensions-tab.component.tsx +590 -0
  372. package/src/components/legacy-reports/tabs/legacy-report-indicators-tab.component.tsx +490 -0
  373. package/src/components/legacy-reports/tabs/legacy-report-json-preview-tab.component.tsx +272 -0
  374. package/src/components/legacy-reports/tabs/legacy-report-overview-tab.component.tsx +218 -0
  375. package/src/components/legacy-reports/tabs/legacy-report-parameters-tab.component.tsx +279 -0
  376. package/src/components/linelist/definition/indicator-to-sql.utils.ts +281 -0
  377. package/src/components/linelist/definition/linelist-definition-editor.component.tsx +1676 -0
  378. package/src/components/linelist/definition/linelist-definition-editor.scss +461 -0
  379. package/src/components/linelist/definition/linelist-definition.types.ts +108 -0
  380. package/src/components/linelist/definition/panels/column-properties-panel.component.tsx +328 -0
  381. package/src/components/linelist/definition/panels/column-selector-panel.component.tsx +1082 -0
  382. package/src/components/linelist/definition/panels/column-selector-panel.scss +100 -0
  383. package/src/components/linelist/definition/panels/custom-sql-column-modal.component.tsx +248 -0
  384. package/src/components/linelist/definition/panels/encounter-diagnosis-column-modal.component.tsx +300 -0
  385. package/src/components/linelist/definition/panels/encounter-diagnosis-column-modal.scss +21 -0
  386. package/src/components/linelist/definition/panels/multi-datasource-selector.component.tsx +332 -0
  387. package/src/components/linelist/definition/panels/multi-datasource-selector.scss +161 -0
  388. package/src/components/linelist/definition/panels/observation-column-modal.component.tsx +450 -0
  389. package/src/components/linelist/definition/panels/observation-column-modal.scss +29 -0
  390. package/src/components/linelist/definition/panels/parameter-panel.component.tsx +659 -0
  391. package/src/components/linelist/definition/panels/parameter-panel.scss +64 -0
  392. package/src/components/linelist/definition/panels/population-source-selector.component.tsx +407 -0
  393. package/src/components/linelist/definition/panels/population-source-selector.scss +187 -0
  394. package/src/components/linelist/design/panels/column-category-selector.component.tsx +433 -0
  395. package/src/components/linelist/design/panels/column-category-selector.scss +324 -0
  396. package/src/components/linelist/design/panels/column-debug-panel.component.tsx +197 -0
  397. package/src/components/linelist/design/panels/column-debug-panel.scss +141 -0
  398. package/src/components/linelist/design/panels/data-catalogue.component.tsx +1062 -0
  399. package/src/components/linelist/design/panels/data-catalogue.scss +263 -0
  400. package/src/components/linelist/design/panels/display-settings-panel.component.tsx +405 -0
  401. package/src/components/linelist/design/panels/display-settings-panel.scss +78 -0
  402. package/src/components/linelist/design/panels/filtermap-editor.component.tsx +434 -0
  403. package/src/components/linelist/design/panels/filtermap-editor.scss +176 -0
  404. package/src/components/linelist/design/panels/json-preview.component.tsx +114 -0
  405. package/src/components/linelist/design/panels/json-preview.scss +85 -0
  406. package/src/components/linelist/design/panels/query-config-panel.component.tsx +1137 -0
  407. package/src/components/linelist/design/panels/query-config-panel.scss +341 -0
  408. package/src/components/linelist/design/panels/sort-config-panel.component.tsx +330 -0
  409. package/src/components/linelist/design/panels/sort-config-panel.scss +77 -0
  410. package/src/components/linelist/design/panels/sql-builder-panel.component.tsx +475 -0
  411. package/src/components/linelist/design/panels/sql-builder-panel.scss +226 -0
  412. package/src/components/linelist/design/panels/transformation-panel.component.tsx +687 -0
  413. package/src/components/linelist/design/panels/transformation-panel.scss +81 -0
  414. package/src/components/linelist/design/panels/visual-filter-panel.component.tsx +595 -0
  415. package/src/components/linelist/design/panels/visual-filter-panel.scss +76 -0
  416. package/src/components/linelist/linelist-dashboard.page.component.tsx +756 -0
  417. package/src/components/linelist/linelist-dashboard.page.scss +240 -0
  418. package/src/components/linelist/linelist-editor.page.component.tsx +134 -0
  419. package/src/components/linelist/linelist-editor.page.scss +28 -0
  420. package/src/components/linelist/linelist-run-report.page.component.tsx +715 -0
  421. package/src/components/linelist/linelist-run-report.page.scss +136 -0
  422. package/src/components/linelist/modals/linelist-report-builder-modal.component.tsx +1454 -0
  423. package/src/components/linelist/modals/linelist-report-builder-modal.scss +164 -0
  424. package/src/components/linelist/modals/preview-parameter-modal.component.tsx +361 -0
  425. package/src/components/report/dashboard/reports-table.component.tsx +186 -0
  426. package/src/components/report/definition/panels/properties-panel.component.tsx +38 -0
  427. package/src/components/report/definition/panels/report-structure-panel.component.tsx +61 -0
  428. package/src/components/report/definition/panels/selection-panel.component.tsx +58 -0
  429. package/src/components/report/definition/report-definition-editor.component.tsx +99 -0
  430. package/src/components/report/definition/report-definition.types.ts +66 -0
  431. package/src/components/report/design/panels/IndicatorPropertiesPanel.scss +33 -0
  432. package/src/components/report/design/panels/IndicatorPropertiesPanel.tsx +389 -0
  433. package/src/components/report/design/panels/JsonPreviewPanel.scss +32 -0
  434. package/src/components/report/design/panels/JsonPreviewPanel.tsx +104 -0
  435. package/src/components/report/design/panels/mapping-preview-panel.component.tsx +82 -0
  436. package/src/components/report/design/panels/mapping-preview-panel.scss +55 -0
  437. package/src/components/report/design/panels/template-structure-panel.component.tsx +296 -0
  438. package/src/components/report/design/panels/template-structure-panel.scss +81 -0
  439. package/src/components/report/design/report-design-editor.component.tsx +1170 -0
  440. package/src/components/report/design/report-design.types.ts +48 -0
  441. package/src/components/report/design/report-design.utils.ts +86 -0
  442. package/src/components/report/panels/report-detail.component.tsx +71 -0
  443. package/src/components/report/panels/report-panel-shell.component.tsx +60 -0
  444. package/src/components/report/report-dashboard.page.component.tsx +554 -0
  445. package/src/components/report/report-editor.page.component.tsx +590 -0
  446. package/src/components/report/report.routes.tsx +32 -0
  447. package/src/components/report-sections/create-report-section-modal.component.tsx +388 -0
  448. package/src/components/report-sections/hooks/useAgeCategories.ts +25 -0
  449. package/src/components/report-sections/hooks/useSectionEditorState.ts +449 -0
  450. package/src/components/report-sections/panels/Dhis2MappingPanel.tsx +157 -0
  451. package/src/components/report-sections/panels/DisaggregationPanel.tsx +97 -0
  452. package/src/components/report-sections/panels/IndicatorPickerPanel.tsx +201 -0
  453. package/src/components/report-sections/panels/SectionBasicsPanel.tsx +27 -0
  454. package/src/components/report-sections/report-section-preview-modal.component.tsx +548 -0
  455. package/src/components/report-sections/report-sections-page.component.tsx +325 -0
  456. package/src/components/report-sections/section-disaggregation.utils.ts +637 -0
  457. package/src/components/report-sections/section-types.ts +55 -0
  458. package/src/components/report-sections/section-utils.ts +50 -0
  459. package/src/components/report-sections/sections-page.scss +79 -0
  460. package/src/components/run-reports/run-reports-page.component.tsx +8 -0
  461. package/src/components/security/access-denied-page.component.tsx +64 -0
  462. package/src/components/security/access-denied-page.scss +39 -0
  463. package/src/components/security/privilege-route.component.test.tsx +76 -0
  464. package/src/components/security/privilege-route.component.tsx +39 -0
  465. package/src/components/shared/compile-setup-modal.component.tsx +182 -0
  466. package/src/components/shared/concept-selector.component.tsx +245 -0
  467. package/src/components/shared/concept-selector.scss +121 -0
  468. package/src/components/shared/header/builder-header-actions.component.tsx +38 -0
  469. package/src/components/shared/header/header.component.tsx +85 -0
  470. package/src/components/shared/header/header.scss +151 -0
  471. package/src/components/shared/header/illustration.component.tsx +34 -0
  472. package/src/components/shared/indicator-properties-panel/IndicatorPropertiesPanel.scss +33 -0
  473. package/src/components/shared/indicator-properties-panel/IndicatorPropertiesPanel.tsx +389 -0
  474. package/src/components/shared/json-preview-panel/JsonPreviewPanel.scss +32 -0
  475. package/src/components/shared/json-preview-panel/JsonPreviewPanel.tsx +104 -0
  476. package/src/components/shared/mapping-preview-panel/mapping-preview-panel.component.tsx +82 -0
  477. package/src/components/shared/mapping-preview-panel/mapping-preview-panel.scss +55 -0
  478. package/src/components/shared/preview/query-results-preview.component.tsx +204 -0
  479. package/src/components/shared/template-structure-panel/template-structure-panel.component.tsx +296 -0
  480. package/src/components/shared/template-structure-panel/template-structure-panel.scss +81 -0
  481. package/src/config-schema.ts +43 -0
  482. package/src/constants/privileges.test.ts +54 -0
  483. package/src/constants/privileges.ts +118 -0
  484. package/src/features/dashboards/DashboardRendererPage.tsx +174 -0
  485. package/src/features/dashboards/DashboardsPage.tsx +164 -0
  486. package/src/features/dashboards/EtlDashboardPage.tsx +32 -0
  487. package/src/features/dashboards/components/DashboardEmptyState.tsx +41 -0
  488. package/src/features/dashboards/components/DashboardGrid.tsx +48 -0
  489. package/src/features/dashboards/components/DashboardHeader.tsx +58 -0
  490. package/src/features/dashboards/components/DashboardSection.tsx +46 -0
  491. package/src/features/dashboards/components/ReportLaunchCard.tsx +51 -0
  492. package/src/features/dashboards/components/WidgetSlotDispatcher.tsx +61 -0
  493. package/src/features/dashboards/components/WidgetUnavailableCard.tsx +36 -0
  494. package/src/features/dashboards/dashboards.scss +196 -0
  495. package/src/features/dashboards/hooks/useDashboard.ts +61 -0
  496. package/src/features/dashboards/hooks/useDashboardWidgets.ts +74 -0
  497. package/src/features/dashboards/hooks/useDashboards.ts +56 -0
  498. package/src/features/dashboards/hooks/useMonitorDataMap.ts +84 -0
  499. package/src/features/dashboards/index.ts +11 -0
  500. package/src/features/dashboards/utils/dashboard-config.util.test.ts +286 -0
  501. package/src/features/dashboards/utils/dashboard-config.util.ts +382 -0
  502. package/src/features/report-visualizer/ReportVisualizerPage.tsx +448 -0
  503. package/src/features/report-visualizer/components/Export/ExportMenu.tsx +141 -0
  504. package/src/features/report-visualizer/components/Export/index.ts +2 -0
  505. package/src/features/report-visualizer/components/ReportExplorer/QuickFilters.tsx +152 -0
  506. package/src/features/report-visualizer/components/ReportExplorer/ReportCategoryFilter.tsx +54 -0
  507. package/src/features/report-visualizer/components/ReportExplorer/ReportExplorerPanel.tsx +201 -0
  508. package/src/features/report-visualizer/components/ReportExplorer/ReportExplorerRail.tsx +202 -0
  509. package/src/features/report-visualizer/components/ReportExplorer/ReportList.tsx +287 -0
  510. package/src/features/report-visualizer/components/ReportExplorer/ReportSearch.tsx +151 -0
  511. package/src/features/report-visualizer/components/ReportExplorer/ReportTagFilter.tsx +100 -0
  512. package/src/features/report-visualizer/components/ReportExplorer/RunReportButton.tsx +42 -0
  513. package/src/features/report-visualizer/components/ReportExplorer/RuntimeParameterForm.tsx +259 -0
  514. package/src/features/report-visualizer/components/ReportExplorer/index.ts +8 -0
  515. package/src/features/report-visualizer/components/ReportWorkspace/ReportLayer.tsx +33 -0
  516. package/src/features/report-visualizer/components/ReportWorkspace/ReportSummary.tsx +88 -0
  517. package/src/features/report-visualizer/components/ReportWorkspace/ReportViewTabs.tsx +72 -0
  518. package/src/features/report-visualizer/components/ReportWorkspace/ReportWorkspaceHeader.tsx +92 -0
  519. package/src/features/report-visualizer/components/ReportWorkspace/ReportWorkspacePanel.tsx +242 -0
  520. package/src/features/report-visualizer/components/ReportWorkspace/index.ts +5 -0
  521. package/src/features/report-visualizer/components/TableView/ColumnVisibilityMenu.tsx +206 -0
  522. package/src/features/report-visualizer/components/TableView/ReportTable.tsx +253 -0
  523. package/src/features/report-visualizer/components/TableView/index.ts +2 -0
  524. package/src/features/report-visualizer/hooks/index.ts +4 -0
  525. package/src/features/report-visualizer/hooks/useExplorerPreferences.ts +103 -0
  526. package/src/features/report-visualizer/hooks/useReportCapabilities.ts +112 -0
  527. package/src/features/report-visualizer/hooks/useReportParameters.ts +152 -0
  528. package/src/features/report-visualizer/hooks/useReports.ts +135 -0
  529. package/src/features/report-visualizer/index.ts +6 -0
  530. package/src/features/report-visualizer/report-visualizer.scss +593 -0
  531. package/src/features/report-visualizer/types/index.ts +1 -0
  532. package/src/features/report-visualizer/types/report-visualizer.types.ts +104 -0
  533. package/src/features/report-visualizer/utils/status-colors.ts +117 -0
  534. package/src/globals.d.ts +9 -0
  535. package/src/hooks/address-template.ts +86 -0
  536. package/src/hooks/concept.ts +112 -0
  537. package/src/hooks/indicator/index.ts +1 -0
  538. package/src/hooks/indicator/useIndicatorsByTheme.ts +41 -0
  539. package/src/hooks/openmrs-reference-data.ts +432 -0
  540. package/src/hooks/theme/index.ts +4 -0
  541. package/src/hooks/theme/useDataTheme.ts +61 -0
  542. package/src/hooks/theme/useDataThemes.ts +28 -0
  543. package/src/hooks/theme/useMambaTableMeta.ts +34 -0
  544. package/src/hooks/theme/useMambaTables.ts +95 -0
  545. package/src/hooks/use-report-builder-privileges.test.tsx +92 -0
  546. package/src/hooks/use-report-builder-privileges.ts +58 -0
  547. package/src/index.ts +29 -0
  548. package/src/resources/address-template/address-template.api.ts +180 -0
  549. package/src/resources/agegroup/agegroups.api.ts +58 -0
  550. package/src/resources/concept/concept.api.ts +116 -0
  551. package/src/resources/concepts/concept-mapper.ts +21 -0
  552. package/src/resources/concepts/concept-types.ts +31 -0
  553. package/src/resources/concepts/concepts.resource.ts +44 -0
  554. package/src/resources/concepts/useConceptSearch.ts +41 -0
  555. package/src/resources/dashboard/dashboard.api.ts +107 -0
  556. package/src/resources/etl-monitor/etl-monitor-test.api.ts +409 -0
  557. package/src/resources/etl-monitor/etl-monitor.api.ts +381 -0
  558. package/src/resources/etl-source/etl-source.api.ts +65 -0
  559. package/src/resources/etl-task/etl-task.api.ts +96 -0
  560. package/src/resources/etl-task/etl-task.types.ts +31 -0
  561. package/src/resources/indicator/indicators.api.ts +125 -0
  562. package/src/resources/legacy-reports/legacy-reports.api.ts +144 -0
  563. package/src/resources/linelist/linelist-reports.api.ts +616 -0
  564. package/src/resources/location/location.api.ts +135 -0
  565. package/src/resources/openmrs-api.ts +40 -0
  566. package/src/resources/patient-identifier-type/patient-identifier-type.api.ts +65 -0
  567. package/src/resources/person-attribute-type/person-attribute-type.api.ts +71 -0
  568. package/src/resources/preview/sql-preview.api.ts +54 -0
  569. package/src/resources/report/reports.api.ts +140 -0
  570. package/src/resources/report-category/report-category.api.ts +41 -0
  571. package/src/resources/report-import-export/import-export-api.ts +164 -0
  572. package/src/resources/report-library/report-library.api.ts +63 -0
  573. package/src/resources/report-section/report-sections.api.ts +73 -0
  574. package/src/resources/report-section/section-preview.api.ts +25 -0
  575. package/src/resources/theme/data-theme.api.ts +88 -0
  576. package/src/resources/theme/etl-schema.api.ts +101 -0
  577. package/src/resources/theme/etl-table-meta.api.ts +45 -0
  578. package/src/root.component.tsx +20 -0
  579. package/src/routes/report-builder.routes.tsx +160 -0
  580. package/src/routes/report-builder.scss +56 -0
  581. package/src/routes.json +31 -0
  582. package/src/sample-template.ts +121 -0
  583. package/src/template-utils.ts +110 -0
  584. package/src/types/carbon-react-inert.d.ts +13 -0
  585. package/src/types/condition-operators.ts +63 -0
  586. package/src/types/dashboard/dashboard.types.ts +137 -0
  587. package/src/types/dashboard/index.ts +4 -0
  588. package/src/types/etl/etl-types.ts +238 -0
  589. package/src/types/etl-monitor/etl-monitor-builder.types.ts +555 -0
  590. package/src/types/etl-monitor/etl-monitor-v2.types.ts +397 -0
  591. package/src/types/etl-monitor/etl-monitor.types.ts +188 -0
  592. package/src/types/etl-monitor/index.ts +6 -0
  593. package/src/types/linelist/compile-config.ts +455 -0
  594. package/src/types/linelist-types.ts +2059 -0
  595. package/src/types/theme/data-theme.types.ts +88 -0
  596. package/src/utils/api-error.utils.test.ts +147 -0
  597. package/src/utils/api-error.utils.ts +131 -0
  598. package/src/utils/config-enhancer.ts +62 -0
  599. package/src/utils/etl-browser/etl-browser.util.test.ts +151 -0
  600. package/src/utils/etl-browser/export-csv.util.ts +43 -0
  601. package/src/utils/etl-browser/group-tables.util.ts +84 -0
  602. package/src/utils/etl-browser/index.ts +4 -0
  603. package/src/utils/etl-browser/summarize-columns.util.ts +27 -0
  604. package/src/utils/etl-browser/table-sql.util.ts +20 -0
  605. package/src/utils/etl-monitor/config-v2-adapter.util.ts +460 -0
  606. package/src/utils/etl-monitor/endpoint-config-normalizer.util.ts +383 -0
  607. package/src/utils/etl-monitor/index.ts +10 -0
  608. package/src/utils/etl-monitor/jsonpath-resolver.util.ts +118 -0
  609. package/src/utils/etl-monitor/normalization-examples.ts +0 -0
  610. package/src/utils/etl-monitor/schema-inspector.util.ts +76 -0
  611. package/src/utils/etl-monitor/semantic-type-detector.util.ts +76 -0
  612. package/src/utils/etl-monitor/status-mapper.util.ts +105 -0
  613. package/src/utils/etl-monitor/value-formatters.util.ts +167 -0
  614. package/src/utils/etl-task/etl-task-card.util.test.ts +240 -0
  615. package/src/utils/etl-task/etl-task-card.util.ts +276 -0
  616. package/src/utils/etl-task/index.ts +1 -0
  617. package/src/utils/html-entities.utils.ts +34 -0
  618. package/src/utils/parameter-resolution.ts +218 -0
  619. package/src/views/etl-monitor-builder/add-monitor-modal.component.scss +0 -0
  620. package/src/views/etl-monitor-builder/add-monitor-modal.component.tsx +210 -0
  621. package/src/views/etl-monitor-builder/etl-monitor-builder.component.scss +157 -0
  622. package/src/views/etl-monitor-builder/etl-monitor-builder.component.tsx +252 -0
  623. package/src/views/etl-monitor-builder/etl-monitor-builder.store.ts +126 -0
  624. package/tools/i18next-parser.config.js +0 -0
  625. package/tools/setup-tests.ts +1 -0
  626. package/tools/update-openmrs-deps.mjs +42 -0
  627. package/translations/am.json +65 -0
  628. package/translations/ar.json +65 -0
  629. package/translations/ar_SY.json +65 -0
  630. package/translations/bn.json +65 -0
  631. package/translations/cs.json +65 -0
  632. package/translations/de.json +65 -0
  633. package/translations/en.json +65 -0
  634. package/translations/en_US.json +65 -0
  635. package/translations/es.json +65 -0
  636. package/translations/es_MX.json +65 -0
  637. package/translations/fr.json +65 -0
  638. package/translations/he.json +65 -0
  639. package/translations/hi.json +65 -0
  640. package/translations/hi_IN.json +65 -0
  641. package/translations/id.json +65 -0
  642. package/translations/it.json +65 -0
  643. package/translations/ka.json +65 -0
  644. package/translations/km.json +65 -0
  645. package/translations/ku.json +65 -0
  646. package/translations/ky.json +65 -0
  647. package/translations/lg.json +65 -0
  648. package/translations/ne.json +65 -0
  649. package/translations/pl.json +65 -0
  650. package/translations/pt.json +65 -0
  651. package/translations/pt_BR.json +65 -0
  652. package/translations/qu.json +65 -0
  653. package/translations/ro_RO.json +65 -0
  654. package/translations/ru_RU.json +65 -0
  655. package/translations/si.json +65 -0
  656. package/translations/sq.json +65 -0
  657. package/translations/sw.json +65 -0
  658. package/translations/sw_KE.json +65 -0
  659. package/translations/tr.json +65 -0
  660. package/translations/tr_TR.json +65 -0
  661. package/translations/uk.json +65 -0
  662. package/translations/uz.json +65 -0
  663. package/translations/uz@Latn.json +65 -0
  664. package/translations/uz_UZ.json +65 -0
  665. package/translations/vi.json +65 -0
  666. package/translations/zh.json +65 -0
  667. package/translations/zh_CN.json +65 -0
  668. package/translations/zh_TW.json +65 -0
  669. package/tsconfig.json +24 -0
  670. package/vitest.config.mts +42 -0
@@ -0,0 +1,381 @@
1
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import { omrsDelete, omrsGet, omrsPost } from '../openmrs-api';
3
+ import type {
4
+ ETLMonitorDto,
5
+ SaveETLMonitorPayload,
6
+ MonitorDataResponse,
7
+ } from '../../types/etl-monitor/etl-monitor.types';
8
+
9
+ type RestList<T> = { results?: T[] } & Record<string, any>;
10
+
11
+ function unwrapRestList<T>(data: RestList<T> | T[] | undefined): T[] {
12
+ if (!data) return [];
13
+ if (Array.isArray(data)) return data;
14
+ return Array.isArray(data.results) ? data.results : [];
15
+ }
16
+
17
+ const RESOURCE = '/reportbuilder/etl-monitor';
18
+
19
+ /**
20
+ * List all ETL monitors
21
+ */
22
+ export async function listETLMonitors(q?: string, signal?: AbortSignal): Promise<ETLMonitorDto[]> {
23
+ const qs = new URLSearchParams();
24
+ qs.set('v', 'full');
25
+ if (q?.trim()) qs.set('q', q.trim());
26
+
27
+ const data = await omrsGet<RestList<ETLMonitorDto> | ETLMonitorDto[] | undefined>(
28
+ `${RESOURCE}?${qs.toString()}`,
29
+ signal,
30
+ );
31
+
32
+ return unwrapRestList(data).filter((x) => Boolean(x?.uuid));
33
+ }
34
+
35
+ /**
36
+ * List active ETL monitors
37
+ */
38
+ export async function listActiveETLMonitors(signal?: AbortSignal): Promise<ETLMonitorDto[]> {
39
+ const qs = new URLSearchParams();
40
+ qs.set('v', 'full');
41
+ qs.set('activeOnly', 'true');
42
+
43
+ const data = await omrsGet<RestList<ETLMonitorDto> | ETLMonitorDto[] | undefined>(
44
+ `${RESOURCE}?${qs.toString()}`,
45
+ signal,
46
+ );
47
+
48
+ return unwrapRestList(data).filter((x) => Boolean(x?.uuid));
49
+ }
50
+
51
+ /**
52
+ * Get ETL monitors by category
53
+ */
54
+ export async function getETLMonitorsByCategory(category: string, signal?: AbortSignal): Promise<ETLMonitorDto[]> {
55
+ const qs = new URLSearchParams();
56
+ qs.set('v', 'full');
57
+ qs.set('category', category);
58
+
59
+ const data = await omrsGet<RestList<ETLMonitorDto> | ETLMonitorDto[] | undefined>(
60
+ `${RESOURCE}?${qs.toString()}`,
61
+ signal,
62
+ );
63
+
64
+ return unwrapRestList(data).filter((x) => Boolean(x?.uuid));
65
+ }
66
+
67
+ /**
68
+ * Get a single ETL monitor by UUID
69
+ */
70
+ export async function getETLMonitor(uuid: string, signal?: AbortSignal): Promise<ETLMonitorDto> {
71
+ const qs = new URLSearchParams();
72
+ qs.set('v', 'full');
73
+
74
+ return omrsGet<ETLMonitorDto>(`${RESOURCE}/${encodeURIComponent(uuid)}?${qs.toString()}`, signal);
75
+ }
76
+
77
+ /**
78
+ * Create a new ETL monitor
79
+ */
80
+ export async function createETLMonitor(payload: SaveETLMonitorPayload, signal?: AbortSignal) {
81
+ return omrsPost<ETLMonitorDto>(RESOURCE, payload, signal);
82
+ }
83
+
84
+ /**
85
+ * Update an existing ETL monitor
86
+ */
87
+ export async function updateETLMonitor(uuid: string, payload: SaveETLMonitorPayload, signal?: AbortSignal) {
88
+ return omrsPost<ETLMonitorDto>(`${RESOURCE}/${encodeURIComponent(uuid)}`, payload, signal);
89
+ }
90
+
91
+ /**
92
+ * Delete/retire an ETL monitor
93
+ */
94
+ export async function deleteETLMonitor(
95
+ uuid: string,
96
+ reason = 'Retired from Report Builder Admin',
97
+ signal?: AbortSignal,
98
+ ) {
99
+ const qs = new URLSearchParams();
100
+ qs.set('reason', reason);
101
+ return omrsDelete(`${RESOURCE}/${encodeURIComponent(uuid)}?${qs.toString()}`, signal);
102
+ }
103
+
104
+ /**
105
+ * Extract value from object using a simple JSONPath-like expression
106
+ * Supports: $.field, $.field.nested, $[0].field
107
+ */
108
+ function extractValue(obj: any, jsonPath: string): any {
109
+ if (!jsonPath || !obj) return undefined;
110
+
111
+ // Remove leading $. if present
112
+ const path = jsonPath.startsWith('$.') ? jsonPath.slice(2) : jsonPath;
113
+
114
+ // Split by . but handle array notation [0]
115
+ const parts = path.split('.').flatMap(p => {
116
+ const arrayMatch = p.match(/^(\w+)\[(\d+)\]$/);
117
+ if (arrayMatch) {
118
+ return [arrayMatch[1], parseInt(arrayMatch[2], 10)];
119
+ }
120
+ return [p];
121
+ });
122
+
123
+ let current = obj;
124
+ for (const part of parts) {
125
+ if (current == null) return undefined;
126
+ current = current[part];
127
+ }
128
+
129
+ return current;
130
+ }
131
+
132
+ /**
133
+ * Transform raw API response using display configuration
134
+ * Converts structured JSON into array of {key, value} objects
135
+ */
136
+ function transformApiResponse(rawResponse: any, displayConfigJson?: string): Array<{
137
+ key: string;
138
+ header: string;
139
+ value: any;
140
+ displayValue?: string;
141
+ rawValue?: any;
142
+ }> {
143
+ if (!rawResponse) return [];
144
+
145
+ // If no display config, try to return array-friendly structure
146
+ if (!displayConfigJson) {
147
+ if (Array.isArray(rawResponse)) {
148
+ return rawResponse;
149
+ }
150
+ // Convert object to array of key-value pairs
151
+ return Object.entries(rawResponse).map(([key, value]) => ({
152
+ key,
153
+ header: key,
154
+ value,
155
+ }));
156
+ }
157
+
158
+ try {
159
+ const config = JSON.parse(displayConfigJson);
160
+ const columns = config.columns || [];
161
+
162
+ return columns.map((col: any) => {
163
+ const value = extractValue(rawResponse, col.jsonPath);
164
+ return {
165
+ key: col.key,
166
+ header: col.header,
167
+ value: value ?? col.defaultValue,
168
+ displayValue: col.format ? applyFormat(value, col.format) : undefined,
169
+ rawValue: value,
170
+ };
171
+ });
172
+ } catch (e) {
173
+ console.error('Failed to parse display config JSON', e);
174
+ return [];
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Apply format string to a value
180
+ */
181
+ function applyFormat(value: any, format: string): string {
182
+ if (value == null) return '';
183
+
184
+ // Handle common format patterns
185
+ if (format.includes('%')) {
186
+ return String(Math.round(Number(value) || 0)) + '%';
187
+ }
188
+ if (format.includes('s')) {
189
+ return String(value) + 's';
190
+ }
191
+ if (format === '0.0') {
192
+ return String(Math.round(Number(value) * 10) / 10);
193
+ }
194
+
195
+ return String(value);
196
+ }
197
+
198
+ /**
199
+ * Fetch data from the external ETL endpoint
200
+ * Uses OpenMRS's openmrsFetch which handles authentication automatically
201
+ */
202
+ export async function fetchMonitorData(uuid: string, signal?: AbortSignal): Promise<MonitorDataResponse> {
203
+ // First, get the monitor configuration
204
+ const monitor = await getETLMonitor(uuid, signal);
205
+
206
+ if (!monitor || !monitor.configJson) {
207
+ throw new Error('Monitor configuration not found');
208
+ }
209
+
210
+ // Parse the config to get the ETL endpoint details
211
+ const config = JSON.parse(monitor.configJson);
212
+ const apiEndpoint = config.apiEndpoint;
213
+
214
+ if (!apiEndpoint || !apiEndpoint.url) {
215
+ throw new Error('ETL endpoint URL not configured');
216
+ }
217
+
218
+ // Construct the URL - if relative, prepend with OpenMRS REST base
219
+ let url = apiEndpoint.url;
220
+ if (url.startsWith('/')) {
221
+ // Prepend with restBaseUrl (/ws/rest/v1) for relative URLs
222
+ url = `${restBaseUrl}${url}`;
223
+ }
224
+
225
+ // Prepare fetch options for openmrsFetch
226
+ const headers: Record<string, string> = {};
227
+
228
+ // Add request body for POST requests
229
+ const body = apiEndpoint.method === 'POST' && apiEndpoint.requestBody
230
+ ? JSON.stringify(apiEndpoint.requestBody)
231
+ : undefined;
232
+
233
+ // Add any custom headers from config
234
+ if (apiEndpoint.headers) {
235
+ Object.entries(apiEndpoint.headers).forEach(([key, value]) => {
236
+ headers[key] = String(value);
237
+ });
238
+ }
239
+
240
+ // Add authentication headers (except for OPENMRS which is handled by openmrsFetch)
241
+ if (apiEndpoint.authType === 'BASIC' && apiEndpoint.authConfig) {
242
+ const credentials = btoa(`${apiEndpoint.authConfig.username}:${apiEndpoint.authConfig.password}`);
243
+ headers['Authorization'] = `Basic ${credentials}`;
244
+ } else if (apiEndpoint.authType === 'BEARER_TOKEN' && apiEndpoint.authConfig?.token) {
245
+ headers['Authorization'] = `Bearer ${apiEndpoint.authConfig.token}`;
246
+ } else if (apiEndpoint.authType === 'API_KEY' && apiEndpoint.authConfig) {
247
+ const { headerName, apiKey } = apiEndpoint.authConfig;
248
+ if (headerName && apiKey) {
249
+ headers[headerName] = apiKey;
250
+ }
251
+ }
252
+
253
+ // Use openmrsFetch which handles OpenMRS session authentication automatically
254
+ const response = await openmrsFetch<any>(url, {
255
+ method: apiEndpoint.method || 'GET',
256
+ headers,
257
+ body,
258
+ signal,
259
+ });
260
+
261
+ // Transform the API response using display configuration
262
+ const transformedData = transformApiResponse(response.data, monitor.displayConfigJson);
263
+
264
+ // Return in the expected format
265
+ return {
266
+ uuid: monitor.uuid,
267
+ code: monitor.code || '',
268
+ timestamp: new Date().toISOString(),
269
+ success: true,
270
+ data: transformedData,
271
+ rawResponse: response.data,
272
+ };
273
+ }
274
+
275
+ /**
276
+ * Test connection to the external ETL endpoint
277
+ * Uses openmrsFetch which handles authentication automatically
278
+ */
279
+ export async function testMonitorConnection(uuid: string, signal?: AbortSignal): Promise<{
280
+ success: boolean;
281
+ message?: string;
282
+ error?: string;
283
+ responseTime?: number;
284
+ }> {
285
+ const startTime = Date.now();
286
+
287
+ try {
288
+ // First, get the monitor configuration
289
+ const monitor = await getETLMonitor(uuid, signal);
290
+
291
+ if (!monitor || !monitor.configJson) {
292
+ return {
293
+ success: false,
294
+ error: 'Monitor configuration not found',
295
+ responseTime: Date.now() - startTime,
296
+ };
297
+ }
298
+
299
+ // Parse the config to get the ETL endpoint details
300
+ const config = JSON.parse(monitor.configJson);
301
+ const apiEndpoint = config.apiEndpoint;
302
+
303
+ if (!apiEndpoint || !apiEndpoint.url) {
304
+ return {
305
+ success: false,
306
+ error: 'ETL endpoint URL not configured',
307
+ responseTime: Date.now() - startTime,
308
+ };
309
+ }
310
+
311
+ // Construct the URL - if relative, prepend with OpenMRS REST base
312
+ let url = apiEndpoint.url;
313
+ if (url.startsWith('/')) {
314
+ // Prepend with restBaseUrl (/ws/rest/v1) for relative URLs
315
+ url = `${restBaseUrl}${url}`;
316
+ }
317
+
318
+ // Prepare fetch options for openmrsFetch
319
+ const headers: Record<string, string> = {};
320
+
321
+ // Add request body for POST requests
322
+ const body = apiEndpoint.method === 'POST' && apiEndpoint.requestBody
323
+ ? JSON.stringify(apiEndpoint.requestBody)
324
+ : undefined;
325
+
326
+ // Add any custom headers from config
327
+ if (apiEndpoint.headers) {
328
+ Object.entries(apiEndpoint.headers).forEach(([key, value]) => {
329
+ headers[key] = String(value);
330
+ });
331
+ }
332
+
333
+ // Add authentication headers (except for OPENMRS which is handled by openmrsFetch)
334
+ if (apiEndpoint.authType === 'BASIC' && apiEndpoint.authConfig) {
335
+ const credentials = btoa(`${apiEndpoint.authConfig.username}:${apiEndpoint.authConfig.password}`);
336
+ headers['Authorization'] = `Basic ${credentials}`;
337
+ } else if (apiEndpoint.authType === 'BEARER_TOKEN' && apiEndpoint.authConfig?.token) {
338
+ headers['Authorization'] = `Bearer ${apiEndpoint.authConfig.token}`;
339
+ } else if (apiEndpoint.authType === 'API_KEY' && apiEndpoint.authConfig) {
340
+ const { headerName, apiKey } = apiEndpoint.authConfig;
341
+ if (headerName && apiKey) {
342
+ headers[headerName] = apiKey;
343
+ }
344
+ }
345
+
346
+ // Use openmrsFetch which handles OpenMRS session authentication automatically
347
+ await openmrsFetch<any>(url, {
348
+ method: apiEndpoint.method || 'GET',
349
+ headers,
350
+ body,
351
+ signal,
352
+ });
353
+ const responseTime = Date.now() - startTime;
354
+
355
+ return {
356
+ success: true,
357
+ message: 'Connection successful',
358
+ responseTime,
359
+ };
360
+
361
+ } catch (error: any) {
362
+ return {
363
+ success: false,
364
+ error: error.message || 'Connection failed',
365
+ responseTime: Date.now() - startTime,
366
+ };
367
+ }
368
+ }
369
+
370
+ // Re-export endpoint test functions
371
+ export {
372
+ testEndpointConnection,
373
+ testEndpointConnectionClientSide,
374
+ isJsonResponse,
375
+ getContentTypeLabel,
376
+ formatDuration,
377
+ formatContentSize,
378
+ getHttpStatusLabel,
379
+ type EndpointTestRequest,
380
+ type EndpointTestResult,
381
+ } from './etl-monitor-test.api';
@@ -0,0 +1,65 @@
1
+ import { omrsDelete, omrsGet, omrsPost } from '../openmrs-api';
2
+
3
+ type RestList<T> = { results?: T[] } & Record<string, any>;
4
+
5
+ function unwrapRestList<T>(data: RestList<T> | T[] | undefined): T[] {
6
+ if (!data) return [];
7
+ if (Array.isArray(data)) return data;
8
+ return Array.isArray(data.results) ? data.results : [];
9
+ }
10
+
11
+ const RESOURCE = '/reportbuilder/etlsource';
12
+
13
+ export type ETLSourceDto = {
14
+ uuid: string;
15
+ display?: string;
16
+ name: string;
17
+ code?: string;
18
+ description?: string;
19
+ tablePatterns?: string;
20
+ schemaName?: string;
21
+ sourceType?: string;
22
+ active?: boolean;
23
+ voided?: boolean;
24
+ };
25
+
26
+ export type SaveETLSourcePayload = {
27
+ name: string;
28
+ code?: string;
29
+ description?: string;
30
+ tablePatterns?: string;
31
+ schemaName?: string;
32
+ sourceType?: string;
33
+ active?: boolean;
34
+ };
35
+
36
+ export async function listETLSources(q?: string, signal?: AbortSignal): Promise<ETLSourceDto[]> {
37
+ const qs = new URLSearchParams();
38
+ qs.set('v', 'custom:(uuid,name,code,description,tablePatterns,schemaName,sourceType,active,retired)');
39
+ if (q?.trim()) qs.set('q', q.trim());
40
+
41
+ const data = await omrsGet<RestList<ETLSourceDto> | ETLSourceDto[] | undefined>(
42
+ `${RESOURCE}?${qs.toString()}`,
43
+ signal,
44
+ );
45
+
46
+ return unwrapRestList(data).filter((x) => Boolean(x?.uuid));
47
+ }
48
+
49
+ export async function createETLSource(payload: SaveETLSourcePayload, signal?: AbortSignal) {
50
+ return omrsPost<ETLSourceDto>(RESOURCE, payload, signal);
51
+ }
52
+
53
+ export async function updateETLSource(uuid: string, payload: SaveETLSourcePayload, signal?: AbortSignal) {
54
+ return omrsPost<ETLSourceDto>(`${RESOURCE}/${encodeURIComponent(uuid)}`, payload, signal);
55
+ }
56
+
57
+ export async function deleteETLSource(
58
+ uuid: string,
59
+ reason = 'Retired from Report Builder Admin',
60
+ signal?: AbortSignal,
61
+ ) {
62
+ const qs = new URLSearchParams();
63
+ qs.set('reason', reason);
64
+ return omrsDelete(`${RESOURCE}/${encodeURIComponent(uuid)}?${qs.toString()}`, signal);
65
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * ETL Task API integration
3
+ * Handles fetching and executing ETL tasks using frontend config
4
+ */
5
+
6
+ import { openmrsFetch } from '@openmrs/esm-framework';
7
+ import type { OpenMRSTaskDefinition, ETLTaskExecutionResponse } from './etl-task.types';
8
+
9
+ // These are OpenMRS core endpoints (scheduler), not reportbuilder ones - a 403 here
10
+ // carries a core privilege name, which the error normalizer passes through verbatim.
11
+ import { guardRejection } from '../../utils/api-error.utils';
12
+
13
+ /**
14
+ * Fetch all available OpenMRS task definitions (with scheduler metadata)
15
+ */
16
+ export async function fetchAllTaskDefinitions(signal?: AbortSignal): Promise<OpenMRSTaskDefinition[]> {
17
+ try {
18
+ const response = await guardRejection(
19
+ openmrsFetch(
20
+ '/ws/rest/v1/taskdefinition?v=custom:(uuid,name,description,taskClass,started,lastExecutionTime,repeatInterval)',
21
+ { signal },
22
+ ),
23
+ );
24
+ const data = await response.json();
25
+ return data.results || [];
26
+ } catch (error) {
27
+ console.error('Error fetching task definitions:', error);
28
+ throw error;
29
+ }
30
+ }
31
+
32
+ export interface ConfiguredTasksResult {
33
+ /** Configured names that matched a task definition, in fetch order */
34
+ tasks: OpenMRSTaskDefinition[];
35
+ /** Configured names with no matching task definition */
36
+ unknownNames: string[];
37
+ }
38
+
39
+ /**
40
+ * Fetch the task definitions for a list of configured task names,
41
+ * partitioning into matched definitions and unknown configured names.
42
+ * Matching is exact and case-sensitive so config typos surface as unknown names.
43
+ */
44
+ export async function fetchConfiguredTasks(
45
+ taskNames: string[],
46
+ signal?: AbortSignal,
47
+ ): Promise<ConfiguredTasksResult> {
48
+ const names = taskNames.map((n) => (typeof n === 'string' ? n.trim() : '')).filter((n) => n);
49
+ if (names.length === 0) return { tasks: [], unknownNames: [] };
50
+
51
+ const allTasks = await fetchAllTaskDefinitions(signal);
52
+
53
+ const matched = new Set<string>();
54
+ const tasks: OpenMRSTaskDefinition[] = [];
55
+ for (const task of allTasks) {
56
+ if (names.includes(task.name)) {
57
+ tasks.push(task);
58
+ matched.add(task.name);
59
+ }
60
+ }
61
+
62
+ const unknownNames = names.filter((n) => !matched.has(n));
63
+ return { tasks, unknownNames };
64
+ }
65
+
66
+ /**
67
+ * Execute an ETL task by name
68
+ */
69
+ export async function executeETLTask(taskName: string): Promise<ETLTaskExecutionResponse> {
70
+ try {
71
+ const response = await guardRejection(
72
+ openmrsFetch('/ws/rest/v1/taskaction', {
73
+ method: 'POST',
74
+ headers: {
75
+ 'Content-Type': 'application/json',
76
+ },
77
+ body: {
78
+ action: 'runtask',
79
+ tasks: [taskName],
80
+ },
81
+ }),
82
+ );
83
+
84
+ if (response.status !== 201) {
85
+ throw new Error(`Task execution failed with status ${response.status}`);
86
+ }
87
+
88
+ return {
89
+ status: response.status,
90
+ message: 'Task executed successfully',
91
+ };
92
+ } catch (error) {
93
+ console.error('Error executing ETL task:', error);
94
+ throw error;
95
+ }
96
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * ETL Task configuration and execution types
3
+ */
4
+
5
+ export interface OpenMRSTaskDefinition {
6
+ uuid: string;
7
+ name: string;
8
+ description?: string;
9
+ taskClass: string;
10
+ /** Whether the task is started in the scheduler */
11
+ started?: boolean;
12
+ /** ISO-ish timestamp of the last execution */
13
+ lastExecutionTime?: string | null;
14
+ /** Repeat interval in seconds; 0/undefined means one-shot */
15
+ repeatInterval?: number | null;
16
+ }
17
+
18
+ /**
19
+ * Shape of the `etlTasks` frontend config option
20
+ */
21
+ export interface ETLTasksConfig {
22
+ /** Names of existing OpenMRS task definitions to list and run */
23
+ tasks: string[];
24
+ /** ETL monitor codes (preferred) or uuids whose live progress shows above the task list */
25
+ progressMonitors?: string[];
26
+ }
27
+
28
+ export interface ETLTaskExecutionResponse {
29
+ status: number;
30
+ message?: string;
31
+ }
@@ -0,0 +1,125 @@
1
+ import { omrsDelete, omrsGet, omrsPost } from '../openmrs-api';
2
+ import { decodeHtmlEntities } from '../../utils/html-entities.utils';
3
+
4
+ /**
5
+ * REST resource:
6
+ * /ws/rest/v1/reportbuilderindicator
7
+ */
8
+ const RESOURCE = '/reportbuilder/indicator';
9
+
10
+ type RestList<T> = { results?: T[] } & Record<string, any>;
11
+
12
+ function unwrapRestList<T>(data: RestList<T> | T[] | undefined): T[] {
13
+ if (!data) return [];
14
+ if (Array.isArray(data)) return data;
15
+ return Array.isArray(data.results) ? data.results : [];
16
+ }
17
+
18
+ function normalizeIndicatorDto(ind: IndicatorDto): IndicatorDto {
19
+ // OpenMRS can return HTML-escaped strings; decode before UI uses them.
20
+ return {
21
+ ...ind,
22
+ configJson: ind.configJson ? decodeHtmlEntities(ind.configJson) : ind.configJson,
23
+ metaJson: ind.metaJson ? decodeHtmlEntities(ind.metaJson) : ind.metaJson,
24
+ sqlTemplate: ind.sqlTemplate ? decodeHtmlEntities(ind.sqlTemplate) : ind.sqlTemplate,
25
+ denominatorSqlTemplate: ind.denominatorSqlTemplate
26
+ ? decodeHtmlEntities(ind.denominatorSqlTemplate)
27
+ : ind.denominatorSqlTemplate,
28
+ };
29
+ }
30
+
31
+ export type IndicatorKind = 'BASE' | 'COMPOSITE' | 'FINAL' | 'CUSTOM';
32
+ export type IndicatorValueType = 'NUMBER' | 'TABLE' | 'PATIENT_SET';
33
+ export type RestRep = 'default' | 'full';
34
+
35
+ export type IndicatorDto = {
36
+ uuid: string;
37
+ name: string;
38
+ description?: string;
39
+ code?: string;
40
+
41
+ kind: IndicatorKind;
42
+ defaultValueType?: IndicatorValueType;
43
+
44
+ // new-ish fields you’re adding backend-side (safe optional)
45
+ themeUuid?: string | null;
46
+ configJson?: string;
47
+ metaJson?: string;
48
+ sqlTemplate?: string | null;
49
+ denominatorSqlTemplate?: string | null;
50
+
51
+ retired?: boolean;
52
+ retireReason?: string | null;
53
+ };
54
+
55
+ export type ETLIndicatorDto = {
56
+ id: string,
57
+ uuid: string;
58
+ name: string;
59
+ description?: string;
60
+ code?: string;
61
+
62
+ kind: IndicatorKind;
63
+ defaultValueType?: IndicatorValueType;
64
+ themeName?: string;
65
+ themeColor?: string;
66
+
67
+ // new-ish fields you’re adding backend-side (safe optional)
68
+ themeUuid?: string | null;
69
+ configJson?: string;
70
+ metaJson?: string;
71
+ sqlTemplate?: string | null;
72
+ denominatorSqlTemplate?: string | null;
73
+
74
+ retired?: boolean;
75
+ retireReason?: string | null;
76
+ };
77
+
78
+ export type ListIndicatorsParams = {
79
+ q?: string;
80
+ kind?: IndicatorKind;
81
+ includeRetired?: boolean;
82
+ v?: RestRep;
83
+ };
84
+
85
+ export async function listIndicators(params?: ListIndicatorsParams, signal?: AbortSignal): Promise<IndicatorDto[]> {
86
+ const q = params?.q?.trim();
87
+ const kind = params?.kind?.trim?.() ? params.kind : params?.kind;
88
+ const includeRetired = params?.includeRetired === true;
89
+ const v = params?.v ?? 'default';
90
+
91
+ const qs = new URLSearchParams();
92
+ qs.set('v', v);
93
+ if (q) qs.set('q', q);
94
+ if (kind) qs.set('kind', kind);
95
+ if (includeRetired) qs.set('includeRetired', 'true');
96
+
97
+ const data = await omrsGet<RestList<IndicatorDto> | IndicatorDto[] | undefined>(`${RESOURCE}?${qs.toString()}`, signal);
98
+
99
+ return unwrapRestList(data)
100
+ .filter((x) => Boolean(x?.uuid))
101
+ .map(normalizeIndicatorDto);
102
+ }
103
+
104
+ export async function getIndicator(uuid: string, signal?: AbortSignal, v: RestRep = 'full'): Promise<IndicatorDto> {
105
+ const res = await omrsGet<IndicatorDto>(`${RESOURCE}/${encodeURIComponent(uuid)}?v=${v}`, signal);
106
+ return normalizeIndicatorDto(res);
107
+ }
108
+
109
+ export async function createIndicator(payload: Partial<IndicatorDto>, signal?: AbortSignal): Promise<IndicatorDto> {
110
+ return omrsPost<IndicatorDto>(RESOURCE, payload, signal);
111
+ }
112
+
113
+ export async function updateIndicator(uuid: string, payload: Partial<IndicatorDto>, signal?: AbortSignal): Promise<IndicatorDto> {
114
+ return omrsPost<IndicatorDto>(`${RESOURCE}/${encodeURIComponent(uuid)}`, payload, signal);
115
+ }
116
+
117
+ export async function deleteIndicator(
118
+ uuid: string,
119
+ purge = false,
120
+ reason = 'Retired via UI',
121
+ signal?: AbortSignal,
122
+ ): Promise<void> {
123
+ const qs = purge ? `purge=true` : `purge=false&reason=${encodeURIComponent(reason)}`;
124
+ await omrsDelete<void>(`${RESOURCE}/${encodeURIComponent(uuid)}?${qs}`, signal);
125
+ }