@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.
- package/.eslintignore +5 -0
- package/.eslintrc.js +19 -0
- package/.prettierrc +8 -0
- package/.tx/config +12 -0
- package/LICENSE +401 -0
- package/README.md +336 -0
- package/__mocks__/react-i18next.js +12 -0
- package/dist/162.js +1 -0
- package/dist/162.js.map +1 -0
- package/dist/184.js +2 -0
- package/dist/184.js.LICENSE.txt +14 -0
- package/dist/184.js.map +1 -0
- package/dist/242.js +2 -0
- package/dist/242.js.LICENSE.txt +21 -0
- package/dist/242.js.map +1 -0
- package/dist/253.js +1 -0
- package/dist/253.js.map +1 -0
- package/dist/300.js +1 -0
- package/dist/311.js +1 -0
- package/dist/311.js.map +1 -0
- package/dist/469.js +2 -0
- package/dist/469.js.LICENSE.txt +45 -0
- package/dist/469.js.map +1 -0
- package/dist/478.js +2 -0
- package/dist/478.js.LICENSE.txt +9 -0
- package/dist/478.js.map +1 -0
- package/dist/539.js +1 -0
- package/dist/539.js.map +1 -0
- package/dist/540.js +2 -0
- package/dist/540.js.LICENSE.txt +9 -0
- package/dist/540.js.map +1 -0
- package/dist/669.js +1 -0
- package/dist/669.js.map +1 -0
- package/dist/710.js +1 -0
- package/dist/710.js.map +1 -0
- package/dist/729.js +1 -0
- package/dist/729.js.map +1 -0
- package/dist/838.js +2 -0
- package/dist/838.js.LICENSE.txt +9 -0
- package/dist/838.js.map +1 -0
- package/dist/917.js +1 -0
- package/dist/917.js.map +1 -0
- package/dist/961.js +2 -0
- package/dist/961.js.LICENSE.txt +19 -0
- package/dist/961.js.map +1 -0
- package/dist/main.js +1 -0
- package/dist/main.js.map +1 -0
- package/dist/openmrs-esm-report-builder.js +1 -0
- package/dist/openmrs-esm-report-builder.js.buildmanifest.json +530 -0
- package/dist/openmrs-esm-report-builder.js.map +1 -0
- package/dist/routes.json +1 -0
- package/e2e/core/env.ts +5 -0
- package/e2e/core/global-setup.ts +34 -0
- package/e2e/core/test.ts +21 -0
- package/e2e/pages/app-shell.page.ts +34 -0
- package/e2e/pages/etl-sources.page.ts +35 -0
- package/e2e/pages/report-sections.page.ts +20 -0
- package/e2e/pages/section-preview.modal.ts +29 -0
- package/e2e/specs/etl-sources.spec.ts +51 -0
- package/e2e/specs/navigation.spec.ts +13 -0
- package/e2e/specs/section-preview-validation.spec.ts +38 -0
- package/e2e/specs/section-preview.spec.ts +94 -0
- package/e2e/support/github/Dockerfile +22 -0
- package/e2e/support/github/Dockerfile.dockerignore +13 -0
- package/e2e/support/github/docker-compose.yml +31 -0
- package/e2e/support/github/run-e2e-docker-env.sh +131 -0
- package/e2e/support/github/spa-assemble-config.json +9 -0
- package/e2e/tsconfig.json +11 -0
- package/example.env +5 -0
- package/jest.config.js +28 -0
- package/linelist_report_builder_design_spec.md +816 -0
- package/package.json +111 -0
- package/playwright.config.ts +28 -0
- package/routes.json +22 -0
- package/src/__debug__/all-designs.test.tsx +30 -0
- package/src/admin-card-link.extension.module.scss +55 -0
- package/src/admin-card-link.extension.tsx +24 -0
- package/src/components/admin/admin-page.component.tsx +75 -0
- package/src/components/admin/age-categories-page.component.tsx +109 -0
- package/src/components/admin/age-groups-page.component.tsx +146 -0
- package/src/components/admin/etl-browser/columns-tab.component.tsx +80 -0
- package/src/components/admin/etl-browser/etl-browser-page.component.tsx +309 -0
- package/src/components/admin/etl-browser/etl-browser.component.scss +424 -0
- package/src/components/admin/etl-browser/metadata-tab.component.tsx +65 -0
- package/src/components/admin/etl-browser/preview-grid.component.tsx +189 -0
- package/src/components/admin/etl-browser/relationships-tab.component.tsx +21 -0
- package/src/components/admin/etl-browser/sources-tree.component.tsx +118 -0
- package/src/components/admin/etl-browser/table-detail.component.tsx +124 -0
- package/src/components/admin/etl-browser/table-info-strip.component.tsx +51 -0
- package/src/components/admin/etl-browser/table-list.component.tsx +136 -0
- package/src/components/admin/etl-browser/use-table-preview.ts +47 -0
- package/src/components/admin/etl-sources-page.component.tsx +355 -0
- package/src/components/admin/etl-tasks-page.component.scss +370 -0
- package/src/components/admin/etl-tasks-page.component.tsx +768 -0
- package/src/components/admin/report-categories-page.component.tsx +267 -0
- package/src/components/admin/report-library-page.component.tsx +551 -0
- package/src/components/ai-support/ai-assist-button.component.tsx +30 -0
- package/src/components/ai-support/ai-assist-modal.component.tsx +81 -0
- package/src/components/ai-support/ai.service.ts +21 -0
- package/src/components/ai-support/ai.types.ts +12 -0
- package/src/components/app-shell/report-builder-shell.component.tsx +242 -0
- package/src/components/app-shell/report-builder-shell.scss +18 -0
- package/src/components/dashboards/dashboard-config.schema.ts +97 -0
- package/src/components/dashboards/dashboard-form-modal.component.tsx +150 -0
- package/src/components/dashboards/dashboards-admin.scss +62 -0
- package/src/components/dashboards/dashboards-page.component.tsx +153 -0
- package/src/components/dashboards/dashboards-table.component.tsx +130 -0
- package/src/components/dashboards/sections/dashboard-autoinclude.section.tsx +75 -0
- package/src/components/dashboards/sections/dashboard-basics.section.tsx +80 -0
- package/src/components/dashboards/sections/dashboard-json.section.tsx +79 -0
- package/src/components/dashboards/sections/dashboard-sections-editor.section.tsx +130 -0
- package/src/components/dashboards/sections/dashboard-widgets-editor.section.tsx +184 -0
- package/src/components/data-themes/data-theme-form.component.tsx +59 -0
- package/src/components/data-themes/data-theme-modal.component.tsx +349 -0
- package/src/components/data-themes/data-themes-page.component.tsx +139 -0
- package/src/components/data-themes/data-themes-table.component.tsx +98 -0
- package/src/components/data-themes/icon-registry.ts +35 -0
- package/src/components/data-themes/sections/data-theme-basics.section.tsx +63 -0
- package/src/components/data-themes/sections/data-theme-condition-columns.section.tsx +397 -0
- package/src/components/data-themes/sections/data-theme-fields-editor.section.tsx +125 -0
- package/src/components/data-themes/sections/data-theme-metadata.section.tsx +245 -0
- package/src/components/data-themes/sections/data-theme-preview.section.tsx +115 -0
- package/src/components/data-themes/sections/data-theme-source.section.tsx +184 -0
- package/src/components/data-visualizer/components/cqi-components/cqi-data-table.component.tsx +214 -0
- package/src/components/data-visualizer/components/cqi-components/cqi-elements.ts +203 -0
- package/src/components/data-visualizer/components/cqi-components/detail.component.tsx +110 -0
- package/src/components/data-visualizer/components/cqi-components/detail.scss +22 -0
- package/src/components/data-visualizer/components/data-table/data-table.component.tsx +208 -0
- package/src/components/data-visualizer/components/data-table/data-tables.scss +206 -0
- package/src/components/data-visualizer/components/empty-state/empty-state-illustration.component.tsx +53 -0
- package/src/components/data-visualizer/components/header/header.component.tsx +43 -0
- package/src/components/data-visualizer/components/header/header.scss +71 -0
- package/src/components/data-visualizer/components/model/confirm.component.tsx +40 -0
- package/src/components/data-visualizer/components/panel/panel.component.tsx +20 -0
- package/src/components/data-visualizer/components/panel/panel.scss +25 -0
- package/src/components/data-visualizer/components/popover/modifier-panel.tsx +53 -0
- package/src/components/data-visualizer/constants.ts +445 -0
- package/src/components/data-visualizer/data-visualizer-illustration.component.tsx +31 -0
- package/src/components/data-visualizer/data-visualizer.component.tsx +1935 -0
- package/src/components/data-visualizer/data-visualizer.resource.ts +462 -0
- package/src/components/data-visualizer/data-visualizer.scss +449 -0
- package/src/components/data-visualizer/declarations.d.ts +131 -0
- package/src/components/data-visualizer/parameter-inputs/boolean-parameter-input.component.tsx +34 -0
- package/src/components/data-visualizer/parameter-inputs/concept-parameter-input.component.tsx +81 -0
- package/src/components/data-visualizer/parameter-inputs/date-parameter-input.component.tsx +110 -0
- package/src/components/data-visualizer/parameter-inputs/date-range-input.component.scss +47 -0
- package/src/components/data-visualizer/parameter-inputs/date-range-input.component.tsx +228 -0
- package/src/components/data-visualizer/parameter-inputs/identifier-type-parameter-input.component.tsx +69 -0
- package/src/components/data-visualizer/parameter-inputs/list-parameter-input.component.tsx +73 -0
- package/src/components/data-visualizer/parameter-inputs/location-parameter-input.component.tsx +81 -0
- package/src/components/data-visualizer/parameter-inputs/number-parameter-input.component.tsx +40 -0
- package/src/components/data-visualizer/parameter-inputs/person-attribute-parameter-input.component.tsx +71 -0
- package/src/components/data-visualizer/parameter-inputs/text-parameter-input.component.tsx +52 -0
- package/src/components/data-visualizer/report-parameter-modal.component.tsx +383 -0
- package/src/components/data-visualizer/types.ts +206 -0
- package/src/components/etl-monitor/builder/builder-state-machine.ts +381 -0
- package/src/components/etl-monitor/builder/design-registry.tsx +139 -0
- package/src/components/etl-monitor/builder/etl-monitor-builder-context.tsx +702 -0
- package/src/components/etl-monitor/builder/etl-monitor-builder-modal.component.tsx +461 -0
- package/src/components/etl-monitor/builder/etl-monitor-builder-modal.scss +256 -0
- package/src/components/etl-monitor/builder/etl-monitor-builder-page.component.tsx +387 -0
- package/src/components/etl-monitor/builder/etl-monitor-builder-page.scss +976 -0
- package/src/components/etl-monitor/builder/generated-config-panel.component.tsx +168 -0
- package/src/components/etl-monitor/builder/generated-config-panel.scss +198 -0
- package/src/components/etl-monitor/builder/index.ts +5 -0
- package/src/components/etl-monitor/builder/monitor-preview.tsx +124 -0
- package/src/components/etl-monitor/builder/steps/data-source-step.component.tsx +667 -0
- package/src/components/etl-monitor/builder/steps/data-source-step.scss +284 -0
- package/src/components/etl-monitor/builder/steps/design-samples.ts +278 -0
- package/src/components/etl-monitor/builder/steps/design-step.component.tsx +299 -0
- package/src/components/etl-monitor/builder/steps/design-step.scss +479 -0
- package/src/components/etl-monitor/builder/steps/fields-step.component.tsx +859 -0
- package/src/components/etl-monitor/builder/steps/fields-step.scss +459 -0
- package/src/components/etl-monitor/builder/steps/general-step.component.tsx +288 -0
- package/src/components/etl-monitor/builder/steps/general-step.scss +103 -0
- package/src/components/etl-monitor/builder/steps/index.ts +5 -0
- package/src/components/etl-monitor/builder/steps/preview-step.component.tsx +245 -0
- package/src/components/etl-monitor/builder/steps/preview-step.scss +236 -0
- package/src/components/etl-monitor/etl-monitor-card-shell.component.tsx +154 -0
- package/src/components/etl-monitor/etl-monitor-card-shell.scss +103 -0
- package/src/components/etl-monitor/etl-monitor-dashboard.component.tsx +227 -0
- package/src/components/etl-monitor/etl-monitor-dashboard.scss +148 -0
- package/src/components/etl-monitor/etl-monitor-status-card.component.tsx +192 -0
- package/src/components/etl-monitor/etl-monitors-page.component.tsx +621 -0
- package/src/components/etl-monitor/renderers/DetailsRenderer.tsx +2 -0
- package/src/components/etl-monitor/renderers/ErrorLogRenderer.tsx +2 -0
- package/src/components/etl-monitor/renderers/EtlMonitorWidget.tsx +97 -0
- package/src/components/etl-monitor/renderers/MetricsGridRenderer.tsx +2 -0
- package/src/components/etl-monitor/renderers/MonitorRenderer.tsx +175 -0
- package/src/components/etl-monitor/renderers/ProgressRenderer.tsx +2 -0
- package/src/components/etl-monitor/renderers/StatusCardRenderer.tsx +2 -0
- package/src/components/etl-monitor/renderers/SummaryCardRenderer.tsx +2 -0
- package/src/components/etl-monitor/renderers/TableRenderer.tsx +2 -0
- package/src/components/etl-monitor/renderers/component-icons.tsx +33 -0
- package/src/components/etl-monitor/renderers/components/details-renderer.tsx +195 -0
- package/src/components/etl-monitor/renderers/components/error-log-renderer.tsx +104 -0
- package/src/components/etl-monitor/renderers/components/index.ts +6 -0
- package/src/components/etl-monitor/renderers/components/log-renderer.tsx +86 -0
- package/src/components/etl-monitor/renderers/components/metrics-grid-renderer.tsx +133 -0
- package/src/components/etl-monitor/renderers/components/progress-renderer.tsx +188 -0
- package/src/components/etl-monitor/renderers/components/status-card-renderer.tsx +247 -0
- package/src/components/etl-monitor/renderers/components/summary-card-renderer.tsx +160 -0
- package/src/components/etl-monitor/renderers/components/table-renderer.tsx +175 -0
- package/src/components/etl-monitor/renderers/components/time-series-renderer.tsx +310 -0
- package/src/components/etl-monitor/renderers/data-transformer.ts +361 -0
- package/src/components/etl-monitor/renderers/index.ts +11 -0
- package/src/components/etl-monitor/renderers/legacy-monitor-renderer.tsx +69 -0
- package/src/components/etl-monitor/renderers/monitor-renderer.tsx +6 -0
- package/src/components/etl-monitor/renderers/monitor-renderers.scss +1621 -0
- package/src/components/etl-monitor/renderers/monitor-widget-card.component.tsx +54 -0
- package/src/components/etl-monitor/renderers/monitor-widget-card.scss +16 -0
- package/src/components/etl-monitor/renderers/v2-monitor-renderer.tsx +227 -0
- package/src/components/import-export/artifact-groups.ts +153 -0
- package/src/components/import-export/export-report-modal.component.tsx +265 -0
- package/src/components/import-export/import-export-page.component.tsx +610 -0
- package/src/components/import-export/import-export.styles.scss +825 -0
- package/src/components/import-export/import-package-modal.component.tsx +401 -0
- package/src/components/import-export/index.ts +3 -0
- package/src/components/indicators/README.md +24 -0
- package/src/components/indicators/base-indicator-basic-fields.component.tsx +18 -0
- package/src/components/indicators/base-indicator-basics.section.tsx +54 -0
- package/src/components/indicators/base-indicator-countby.section.tsx +25 -0
- package/src/components/indicators/base-indicator-criteria.section.tsx +83 -0
- package/src/components/indicators/base-indicator-details-form.component.tsx +80 -0
- package/src/components/indicators/base-indicator-theme-unit-fields.component.tsx +39 -0
- package/src/components/indicators/create-base-indicator-modal.component.tsx +623 -0
- package/src/components/indicators/create-composite-base-indicator-modal.component.tsx +295 -0
- package/src/components/indicators/create-custom-indicator-modal.component.tsx +548 -0
- package/src/components/indicators/create-final-indicator-modal.component.tsx +285 -0
- package/src/components/indicators/custom-condition-input.component.tsx +310 -0
- package/src/components/indicators/diagnosis-filters-form.component.tsx +101 -0
- package/src/components/indicators/disaggregation-panel.component.tsx +93 -0
- package/src/components/indicators/handler/concept-search-multiselect.component.tsx +153 -0
- package/src/components/indicators/handler/question-answer-concept-search.component.tsx +336 -0
- package/src/components/indicators/indicator-run-preview-modal.component.tsx +391 -0
- package/src/components/indicators/indicator-search-select.component.tsx +297 -0
- package/src/components/indicators/indicator-status-tag.component.tsx +9 -0
- package/src/components/indicators/indicators-page.component.tsx +673 -0
- package/src/components/indicators/indicators-page.scss +121 -0
- package/src/components/indicators/indicators-table.component.tsx +188 -0
- package/src/components/indicators/preview-table.component.tsx +31 -0
- package/src/components/indicators/sections/composite-indicator-basics.section.tsx +36 -0
- package/src/components/indicators/sections/composite-indicator-picker.section.tsx +116 -0
- package/src/components/indicators/sections/composite-indicator-sql-preview.section.tsx +31 -0
- package/src/components/indicators/sections/custom-indicator-basics.section.tsx +65 -0
- package/src/components/indicators/sections/custom-indicator-disaggregation.section.tsx +93 -0
- package/src/components/indicators/sections/custom-indicator-filters.section.tsx +203 -0
- package/src/components/indicators/sections/custom-indicator-population.section.tsx +107 -0
- package/src/components/indicators/sections/custom-indicator-sql-preview.section.tsx +108 -0
- package/src/components/indicators/sections/final-indicator-basics.section.tsx +46 -0
- package/src/components/indicators/sections/final-indicator-disaggregation.section.tsx +47 -0
- package/src/components/indicators/sections/final-indicator-picker.section.tsx +60 -0
- package/src/components/indicators/sections/final-indicator-preview.section.tsx +20 -0
- package/src/components/indicators/sections/final-indicator-results-preview.section.tsx +65 -0
- package/src/components/indicators/sections/indicator-basics.section.tsx +40 -0
- package/src/components/indicators/sections/indicator-conditions.section.tsx +279 -0
- package/src/components/indicators/sections/indicator-sql-preview.section.tsx +63 -0
- package/src/components/indicators/sections/indicator-theme.section.tsx +48 -0
- package/src/components/indicators/sql-preview.component.tsx +19 -0
- package/src/components/indicators/tag-input.component.tsx +177 -0
- package/src/components/indicators/types/base-indicator-form.types.ts +17 -0
- package/src/components/indicators/types/base-indicator-theme.constants.ts +8 -0
- package/src/components/indicators/types/composite-indicator.types.ts +27 -0
- package/src/components/indicators/types/condition-ui.types.ts +11 -0
- package/src/components/indicators/types/custom-indicator.types.ts +161 -0
- package/src/components/indicators/types/data-theme-config.types.ts +88 -0
- package/src/components/indicators/types/indicator-types.ts +57 -0
- package/src/components/indicators/types/sql-builders.ts +43 -0
- package/src/components/indicators/utils/composite-indicator-sql.utils.test.ts +143 -0
- package/src/components/indicators/utils/composite-indicator-sql.utils.ts +426 -0
- package/src/components/indicators/utils/concept-preload.utils.ts +21 -0
- package/src/components/indicators/utils/custom-indicator-interpreter.test.ts +493 -0
- package/src/components/indicators/utils/custom-indicator-interpreter.ts +702 -0
- package/src/components/indicators/utils/final-indicator-sql.utils.ts +190 -0
- package/src/components/indicators/utils/indicator-conditions-hydration.utils.ts +254 -0
- package/src/components/indicators/utils/indicator-sql-resolution.utils.ts +204 -0
- package/src/components/indicators/utils/indicator-sql.utils.ts +721 -0
- package/src/components/indicators/utils/population-sql.compiler.test.ts +999 -0
- package/src/components/indicators/utils/population-sql.compiler.ts +858 -0
- package/src/components/landing/landing-action-item.component.tsx +50 -0
- package/src/components/landing/landing-action-list.component.tsx +12 -0
- package/src/components/landing/landing-activity-list.component.tsx +47 -0
- package/src/components/landing/landing-footer-grid.component.tsx +45 -0
- package/src/components/landing/landing-hero.component.tsx +18 -0
- package/src/components/landing/landing-section-card.component.tsx +33 -0
- package/src/components/landing/report-builder-landing-page.component.tsx +186 -0
- package/src/components/landing/report-builder-landing-page.scss +131 -0
- package/src/components/legacy-reports/legacy-report-detail-page.component.tsx +300 -0
- package/src/components/legacy-reports/legacy-report-editor-page.component.tsx +324 -0
- package/src/components/legacy-reports/legacy-report-upload-modal.component.tsx +307 -0
- package/src/components/legacy-reports/legacy-reports-page.component.tsx +206 -0
- package/src/components/legacy-reports/legacy-reports-table.component.tsx +154 -0
- package/src/components/legacy-reports/tabs/legacy-report-datasets-tab.component.tsx +344 -0
- package/src/components/legacy-reports/tabs/legacy-report-dimensions-tab.component.tsx +590 -0
- package/src/components/legacy-reports/tabs/legacy-report-indicators-tab.component.tsx +490 -0
- package/src/components/legacy-reports/tabs/legacy-report-json-preview-tab.component.tsx +272 -0
- package/src/components/legacy-reports/tabs/legacy-report-overview-tab.component.tsx +218 -0
- package/src/components/legacy-reports/tabs/legacy-report-parameters-tab.component.tsx +279 -0
- package/src/components/linelist/definition/indicator-to-sql.utils.ts +281 -0
- package/src/components/linelist/definition/linelist-definition-editor.component.tsx +1676 -0
- package/src/components/linelist/definition/linelist-definition-editor.scss +461 -0
- package/src/components/linelist/definition/linelist-definition.types.ts +108 -0
- package/src/components/linelist/definition/panels/column-properties-panel.component.tsx +328 -0
- package/src/components/linelist/definition/panels/column-selector-panel.component.tsx +1082 -0
- package/src/components/linelist/definition/panels/column-selector-panel.scss +100 -0
- package/src/components/linelist/definition/panels/custom-sql-column-modal.component.tsx +248 -0
- package/src/components/linelist/definition/panels/encounter-diagnosis-column-modal.component.tsx +300 -0
- package/src/components/linelist/definition/panels/encounter-diagnosis-column-modal.scss +21 -0
- package/src/components/linelist/definition/panels/multi-datasource-selector.component.tsx +332 -0
- package/src/components/linelist/definition/panels/multi-datasource-selector.scss +161 -0
- package/src/components/linelist/definition/panels/observation-column-modal.component.tsx +450 -0
- package/src/components/linelist/definition/panels/observation-column-modal.scss +29 -0
- package/src/components/linelist/definition/panels/parameter-panel.component.tsx +659 -0
- package/src/components/linelist/definition/panels/parameter-panel.scss +64 -0
- package/src/components/linelist/definition/panels/population-source-selector.component.tsx +407 -0
- package/src/components/linelist/definition/panels/population-source-selector.scss +187 -0
- package/src/components/linelist/design/panels/column-category-selector.component.tsx +433 -0
- package/src/components/linelist/design/panels/column-category-selector.scss +329 -0
- package/src/components/linelist/design/panels/column-debug-panel.component.tsx +197 -0
- package/src/components/linelist/design/panels/column-debug-panel.scss +141 -0
- package/src/components/linelist/design/panels/data-catalogue.component.tsx +1062 -0
- package/src/components/linelist/design/panels/data-catalogue.scss +263 -0
- package/src/components/linelist/design/panels/display-settings-panel.component.tsx +405 -0
- package/src/components/linelist/design/panels/display-settings-panel.scss +78 -0
- package/src/components/linelist/design/panels/filtermap-editor.component.tsx +434 -0
- package/src/components/linelist/design/panels/filtermap-editor.scss +176 -0
- package/src/components/linelist/design/panels/json-preview.component.tsx +114 -0
- package/src/components/linelist/design/panels/json-preview.scss +85 -0
- package/src/components/linelist/design/panels/query-config-panel.component.tsx +1137 -0
- package/src/components/linelist/design/panels/query-config-panel.scss +342 -0
- package/src/components/linelist/design/panels/sort-config-panel.component.tsx +330 -0
- package/src/components/linelist/design/panels/sort-config-panel.scss +77 -0
- package/src/components/linelist/design/panels/sql-builder-panel.component.tsx +475 -0
- package/src/components/linelist/design/panels/sql-builder-panel.scss +226 -0
- package/src/components/linelist/design/panels/transformation-panel.component.tsx +687 -0
- package/src/components/linelist/design/panels/transformation-panel.scss +81 -0
- package/src/components/linelist/design/panels/visual-filter-panel.component.tsx +595 -0
- package/src/components/linelist/design/panels/visual-filter-panel.scss +76 -0
- package/src/components/linelist/linelist-dashboard.page.component.tsx +756 -0
- package/src/components/linelist/linelist-dashboard.page.scss +240 -0
- package/src/components/linelist/linelist-editor.page.component.tsx +134 -0
- package/src/components/linelist/linelist-editor.page.scss +28 -0
- package/src/components/linelist/linelist-run-report.page.component.tsx +715 -0
- package/src/components/linelist/linelist-run-report.page.scss +136 -0
- package/src/components/linelist/modals/linelist-report-builder-modal.component.tsx +1454 -0
- package/src/components/linelist/modals/linelist-report-builder-modal.scss +164 -0
- package/src/components/linelist/modals/preview-parameter-modal.component.tsx +361 -0
- package/src/components/report/dashboard/reports-table.component.tsx +186 -0
- package/src/components/report/definition/panels/properties-panel.component.tsx +38 -0
- package/src/components/report/definition/panels/report-structure-panel.component.tsx +61 -0
- package/src/components/report/definition/panels/selection-panel.component.tsx +58 -0
- package/src/components/report/definition/report-definition-editor.component.tsx +99 -0
- package/src/components/report/definition/report-definition.types.ts +66 -0
- package/src/components/report/design/panels/IndicatorPropertiesPanel.scss +33 -0
- package/src/components/report/design/panels/IndicatorPropertiesPanel.tsx +389 -0
- package/src/components/report/design/panels/JsonPreviewPanel.scss +32 -0
- package/src/components/report/design/panels/JsonPreviewPanel.tsx +104 -0
- package/src/components/report/design/panels/mapping-preview-panel.component.tsx +82 -0
- package/src/components/report/design/panels/mapping-preview-panel.scss +55 -0
- package/src/components/report/design/panels/template-structure-panel.component.tsx +296 -0
- package/src/components/report/design/panels/template-structure-panel.scss +81 -0
- package/src/components/report/design/report-design-editor.component.tsx +1170 -0
- package/src/components/report/design/report-design.types.ts +48 -0
- package/src/components/report/design/report-design.utils.ts +86 -0
- package/src/components/report/panels/report-detail.component.tsx +71 -0
- package/src/components/report/panels/report-panel-shell.component.tsx +60 -0
- package/src/components/report/report-dashboard.page.component.tsx +554 -0
- package/src/components/report/report-editor.page.component.tsx +590 -0
- package/src/components/report/report.routes.tsx +32 -0
- package/src/components/report-sections/create-report-section-modal.component.tsx +388 -0
- package/src/components/report-sections/hooks/useAgeCategories.ts +25 -0
- package/src/components/report-sections/hooks/useSectionEditorState.ts +449 -0
- package/src/components/report-sections/panels/Dhis2MappingPanel.tsx +157 -0
- package/src/components/report-sections/panels/DisaggregationPanel.tsx +97 -0
- package/src/components/report-sections/panels/IndicatorPickerPanel.tsx +201 -0
- package/src/components/report-sections/panels/SectionBasicsPanel.tsx +27 -0
- package/src/components/report-sections/report-section-preview-modal.component.tsx +548 -0
- package/src/components/report-sections/report-sections-page.component.tsx +325 -0
- package/src/components/report-sections/section-disaggregation.utils.ts +637 -0
- package/src/components/report-sections/section-types.ts +55 -0
- package/src/components/report-sections/section-utils.ts +50 -0
- package/src/components/report-sections/sections-page.scss +79 -0
- package/src/components/run-reports/run-reports-page.component.tsx +8 -0
- package/src/components/security/access-denied-page.component.tsx +69 -0
- package/src/components/security/access-denied-page.scss +39 -0
- package/src/components/security/privilege-route.component.test.tsx +79 -0
- package/src/components/security/privilege-route.component.tsx +39 -0
- package/src/components/shared/compile-setup-modal.component.tsx +182 -0
- package/src/components/shared/concept-selector.component.tsx +245 -0
- package/src/components/shared/concept-selector.scss +121 -0
- package/src/components/shared/header/builder-header-actions.component.tsx +38 -0
- package/src/components/shared/header/header.component.tsx +85 -0
- package/src/components/shared/header/header.scss +150 -0
- package/src/components/shared/header/illustration.component.tsx +34 -0
- package/src/components/shared/indicator-properties-panel/IndicatorPropertiesPanel.scss +33 -0
- package/src/components/shared/indicator-properties-panel/IndicatorPropertiesPanel.tsx +389 -0
- package/src/components/shared/json-preview-panel/JsonPreviewPanel.scss +32 -0
- package/src/components/shared/json-preview-panel/JsonPreviewPanel.tsx +104 -0
- package/src/components/shared/mapping-preview-panel/mapping-preview-panel.component.tsx +82 -0
- package/src/components/shared/mapping-preview-panel/mapping-preview-panel.scss +55 -0
- package/src/components/shared/preview/query-results-preview.component.tsx +204 -0
- package/src/components/shared/template-structure-panel/template-structure-panel.component.tsx +296 -0
- package/src/components/shared/template-structure-panel/template-structure-panel.scss +81 -0
- package/src/config-schema.ts +43 -0
- package/src/constants/privileges.test.ts +53 -0
- package/src/constants/privileges.ts +118 -0
- package/src/features/dashboards/DashboardRendererPage.tsx +174 -0
- package/src/features/dashboards/DashboardsPage.tsx +164 -0
- package/src/features/dashboards/EtlDashboardPage.tsx +32 -0
- package/src/features/dashboards/components/DashboardEmptyState.tsx +41 -0
- package/src/features/dashboards/components/DashboardGrid.tsx +48 -0
- package/src/features/dashboards/components/DashboardHeader.tsx +58 -0
- package/src/features/dashboards/components/DashboardSection.tsx +46 -0
- package/src/features/dashboards/components/ReportLaunchCard.tsx +51 -0
- package/src/features/dashboards/components/WidgetSlotDispatcher.tsx +61 -0
- package/src/features/dashboards/components/WidgetUnavailableCard.tsx +36 -0
- package/src/features/dashboards/dashboards.scss +196 -0
- package/src/features/dashboards/hooks/useDashboard.ts +61 -0
- package/src/features/dashboards/hooks/useDashboardWidgets.ts +74 -0
- package/src/features/dashboards/hooks/useDashboards.ts +56 -0
- package/src/features/dashboards/hooks/useMonitorDataMap.ts +84 -0
- package/src/features/dashboards/index.ts +11 -0
- package/src/features/dashboards/utils/dashboard-config.util.test.ts +255 -0
- package/src/features/dashboards/utils/dashboard-config.util.ts +382 -0
- package/src/features/report-visualizer/ReportVisualizerPage.tsx +448 -0
- package/src/features/report-visualizer/components/Export/ExportMenu.tsx +141 -0
- package/src/features/report-visualizer/components/Export/index.ts +2 -0
- package/src/features/report-visualizer/components/ReportExplorer/QuickFilters.tsx +152 -0
- package/src/features/report-visualizer/components/ReportExplorer/ReportCategoryFilter.tsx +54 -0
- package/src/features/report-visualizer/components/ReportExplorer/ReportExplorerPanel.tsx +201 -0
- package/src/features/report-visualizer/components/ReportExplorer/ReportExplorerRail.tsx +202 -0
- package/src/features/report-visualizer/components/ReportExplorer/ReportList.tsx +287 -0
- package/src/features/report-visualizer/components/ReportExplorer/ReportSearch.tsx +151 -0
- package/src/features/report-visualizer/components/ReportExplorer/ReportTagFilter.tsx +100 -0
- package/src/features/report-visualizer/components/ReportExplorer/RunReportButton.tsx +42 -0
- package/src/features/report-visualizer/components/ReportExplorer/RuntimeParameterForm.tsx +259 -0
- package/src/features/report-visualizer/components/ReportExplorer/index.ts +8 -0
- package/src/features/report-visualizer/components/ReportWorkspace/ReportLayer.tsx +33 -0
- package/src/features/report-visualizer/components/ReportWorkspace/ReportSummary.tsx +88 -0
- package/src/features/report-visualizer/components/ReportWorkspace/ReportViewTabs.tsx +72 -0
- package/src/features/report-visualizer/components/ReportWorkspace/ReportWorkspaceHeader.tsx +92 -0
- package/src/features/report-visualizer/components/ReportWorkspace/ReportWorkspacePanel.tsx +242 -0
- package/src/features/report-visualizer/components/ReportWorkspace/index.ts +5 -0
- package/src/features/report-visualizer/components/TableView/ColumnVisibilityMenu.tsx +206 -0
- package/src/features/report-visualizer/components/TableView/ReportTable.tsx +253 -0
- package/src/features/report-visualizer/components/TableView/index.ts +2 -0
- package/src/features/report-visualizer/hooks/index.ts +4 -0
- package/src/features/report-visualizer/hooks/useExplorerPreferences.ts +103 -0
- package/src/features/report-visualizer/hooks/useReportCapabilities.ts +112 -0
- package/src/features/report-visualizer/hooks/useReportParameters.ts +152 -0
- package/src/features/report-visualizer/hooks/useReports.ts +135 -0
- package/src/features/report-visualizer/index.ts +6 -0
- package/src/features/report-visualizer/report-visualizer.scss +593 -0
- package/src/features/report-visualizer/types/index.ts +1 -0
- package/src/features/report-visualizer/types/report-visualizer.types.ts +104 -0
- package/src/features/report-visualizer/utils/status-colors.ts +117 -0
- package/src/globals.d.ts +14 -0
- package/src/hooks/address-template.ts +86 -0
- package/src/hooks/concept.ts +112 -0
- package/src/hooks/indicator/index.ts +1 -0
- package/src/hooks/indicator/useIndicatorsByTheme.ts +41 -0
- package/src/hooks/openmrs-reference-data.ts +432 -0
- package/src/hooks/theme/index.ts +4 -0
- package/src/hooks/theme/useDataTheme.ts +61 -0
- package/src/hooks/theme/useDataThemes.ts +28 -0
- package/src/hooks/theme/useMambaTableMeta.ts +34 -0
- package/src/hooks/theme/useMambaTables.ts +95 -0
- package/src/hooks/use-report-builder-privileges.test.tsx +98 -0
- package/src/hooks/use-report-builder-privileges.ts +58 -0
- package/src/index.ts +29 -0
- package/src/resources/address-template/address-template.api.ts +180 -0
- package/src/resources/agegroup/agegroups.api.ts +58 -0
- package/src/resources/concept/concept.api.ts +116 -0
- package/src/resources/concepts/concept-mapper.ts +21 -0
- package/src/resources/concepts/concept-types.ts +31 -0
- package/src/resources/concepts/concepts.resource.ts +44 -0
- package/src/resources/concepts/useConceptSearch.ts +41 -0
- package/src/resources/dashboard/dashboard.api.ts +107 -0
- package/src/resources/etl-monitor/etl-monitor-test.api.ts +409 -0
- package/src/resources/etl-monitor/etl-monitor.api.ts +381 -0
- package/src/resources/etl-source/etl-source.api.ts +65 -0
- package/src/resources/etl-task/etl-task.api.ts +96 -0
- package/src/resources/etl-task/etl-task.types.ts +31 -0
- package/src/resources/indicator/indicators.api.ts +125 -0
- package/src/resources/legacy-reports/legacy-reports.api.ts +144 -0
- package/src/resources/linelist/linelist-reports.api.ts +616 -0
- package/src/resources/location/location.api.ts +135 -0
- package/src/resources/openmrs-api.ts +40 -0
- package/src/resources/patient-identifier-type/patient-identifier-type.api.ts +65 -0
- package/src/resources/person-attribute-type/person-attribute-type.api.ts +71 -0
- package/src/resources/preview/sql-preview.api.ts +54 -0
- package/src/resources/report/reports.api.ts +140 -0
- package/src/resources/report-category/report-category.api.ts +41 -0
- package/src/resources/report-import-export/import-export-api.ts +164 -0
- package/src/resources/report-library/report-library.api.ts +63 -0
- package/src/resources/report-section/report-sections.api.ts +73 -0
- package/src/resources/report-section/section-preview.api.ts +25 -0
- package/src/resources/theme/data-theme.api.ts +88 -0
- package/src/resources/theme/etl-schema.api.ts +101 -0
- package/src/resources/theme/etl-table-meta.api.ts +45 -0
- package/src/root.component.tsx +20 -0
- package/src/routes/report-builder.routes.tsx +160 -0
- package/src/routes/report-builder.scss +56 -0
- package/src/routes.json +28 -0
- package/src/sample-template.ts +121 -0
- package/src/template-utils.ts +110 -0
- package/src/types/carbon-react-inert.d.ts +13 -0
- package/src/types/condition-operators.ts +63 -0
- package/src/types/dashboard/dashboard.types.ts +137 -0
- package/src/types/dashboard/index.ts +4 -0
- package/src/types/etl/etl-types.ts +238 -0
- package/src/types/etl-monitor/etl-monitor-builder.types.ts +555 -0
- package/src/types/etl-monitor/etl-monitor-v2.types.ts +397 -0
- package/src/types/etl-monitor/etl-monitor.types.ts +188 -0
- package/src/types/etl-monitor/index.ts +6 -0
- package/src/types/linelist/compile-config.ts +455 -0
- package/src/types/linelist-types.ts +2059 -0
- package/src/types/theme/data-theme.types.ts +88 -0
- package/src/utils/api-error.utils.test.ts +151 -0
- package/src/utils/api-error.utils.ts +131 -0
- package/src/utils/config-enhancer.ts +62 -0
- package/src/utils/etl-browser/etl-browser.util.test.ts +145 -0
- package/src/utils/etl-browser/export-csv.util.ts +43 -0
- package/src/utils/etl-browser/group-tables.util.ts +84 -0
- package/src/utils/etl-browser/index.ts +4 -0
- package/src/utils/etl-browser/summarize-columns.util.ts +27 -0
- package/src/utils/etl-browser/table-sql.util.ts +20 -0
- package/src/utils/etl-monitor/config-v2-adapter.util.ts +460 -0
- package/src/utils/etl-monitor/endpoint-config-normalizer.util.ts +383 -0
- package/src/utils/etl-monitor/index.ts +10 -0
- package/src/utils/etl-monitor/jsonpath-resolver.util.ts +118 -0
- package/src/utils/etl-monitor/normalization-examples.ts +0 -0
- package/src/utils/etl-monitor/schema-inspector.util.ts +76 -0
- package/src/utils/etl-monitor/semantic-type-detector.util.ts +76 -0
- package/src/utils/etl-monitor/status-mapper.util.ts +105 -0
- package/src/utils/etl-monitor/value-formatters.util.ts +167 -0
- package/src/utils/etl-task/etl-task-card.util.test.ts +239 -0
- package/src/utils/etl-task/etl-task-card.util.ts +276 -0
- package/src/utils/etl-task/index.ts +1 -0
- package/src/utils/html-entities.utils.ts +34 -0
- package/src/utils/parameter-resolution.ts +218 -0
- package/src/views/etl-monitor-builder/add-monitor-modal.component.scss +0 -0
- package/src/views/etl-monitor-builder/add-monitor-modal.component.tsx +210 -0
- package/src/views/etl-monitor-builder/etl-monitor-builder.component.scss +157 -0
- package/src/views/etl-monitor-builder/etl-monitor-builder.component.tsx +252 -0
- package/src/views/etl-monitor-builder/etl-monitor-builder.store.ts +126 -0
- package/tools/scss-stub.js +12 -0
- package/tools/setup-tests.ts +1 -0
- package/translations/en.json +65 -0
- package/tsconfig.json +43 -0
- package/webpack.config.js +30 -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
|
+
}
|