From 8f28703ae8b56cfee283ec1ce0ec2b13dfd91e30 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Sun, 26 Nov 2023 02:37:35 +0100 Subject: [PATCH 01/32] fix(translations): sync translations from transifex (master) Automatically merged. --- i18n/uz_UZ_Cyrl.po | 77 +++++++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/i18n/uz_UZ_Cyrl.po b/i18n/uz_UZ_Cyrl.po index 7d62b3a5cd..620b5591f9 100644 --- a/i18n/uz_UZ_Cyrl.po +++ b/i18n/uz_UZ_Cyrl.po @@ -177,6 +177,7 @@ msgstr "" msgid "Saving a {{trackedEntityName}} in {{programName}} in {{orgUnitName}}." msgstr "" +"Сақланмоқда {{trackedEntityName}} да {{programName}} да {{orgUnitName}}." msgid "Cancel" msgstr "Бекор қилиш" @@ -212,7 +213,7 @@ msgid "Assignee" msgstr "Ваколат берилган шахс" msgid "Saving to {{programName}} in {{orgUnitName}}" -msgstr "" +msgstr "Сақланади {{programName}} да {{orgUnitName}}" msgid "" "This is not an event program or the metadata is corrupt. See log for " @@ -250,7 +251,7 @@ msgid "Finish" msgstr "Тугатиш" msgid "Save without completing" -msgstr "" +msgstr "Тугалланмасдан сақлаш" msgid "Complete" msgstr "Тўлдириш" @@ -673,36 +674,38 @@ msgid "" msgstr "" msgid "Enrollment Dashboard" -msgstr "" +msgstr "Қайд этиш панели" msgid "No indicator output for this enrollment yet" -msgstr "" +msgstr "Ушбу қайд этишда индикатор ахбороти мавжуд эмас" msgid "No feedback for this enrollment yet" -msgstr "" +msgstr "Ушбу қайд этишда қайта алоқа ахбороти мавжуд эмас" msgid "Quick actions" -msgstr "" +msgstr "Тезкор харакатлар" msgid "New Event" -msgstr "" +msgstr "Янги Ҳодиса/Ҳолат" msgid "Schedule an event" -msgstr "" +msgstr "Ҳодиса/Ҳолатни режалаш" msgid "Make referral" msgstr "Йўналиш яратинг" msgid "No available program stages" -msgstr "" +msgstr "Дастур босқичлари мавжуд эмас" msgid "Program stage not found" -msgstr "" +msgstr "Дастур босқичлари топилмади" msgid "" "Choose a program to add new or see existing enrollments for " "{{teiDisplayName}}" msgstr "" +" {{teiDisplayName}} учун янги рўйхатга ёки мавжуд рўйхатга олишларини кўриш " +"учун дастурни танланг." msgid "" "{{programName}} has categories. Choose all categories to view dashboard." @@ -713,7 +716,7 @@ msgid "Invalid enrollment id {{enrollmentId}}." msgstr "" msgid "Choose an enrollment to view the dashboard." -msgstr "" +msgstr "бошқарув панелини кўриш учун рўйхатдан ўтишни танланг." msgid "There are no active enrollments." msgstr "" @@ -751,19 +754,19 @@ msgid "View working list in this program." msgstr "Ушбу дастурдаги ишчи рўйхатни кўриб чиқиш" msgid "Page is missing required values from URL" -msgstr "" +msgstr "URL саҳифасида керакли қийматлар йўқ" msgid "Program is not valid" -msgstr "" +msgstr "Дастур яроқли эмас" msgid "Org unit is not valid with current program" -msgstr "" +msgstr "Жорий дастур учун ташкилий бирлик яроқли эмас" msgid "There was an error opening the Page" -msgstr "" +msgstr "Саҳифани очишда хатолик мавжуд" msgid "Enrollment{{escape}} New Event" -msgstr "" +msgstr "Рўйхатга олишда {{escape}} Янги Ҳодиса/Ҳолат" msgid "There was an error loading the page" msgstr "" @@ -1174,6 +1177,33 @@ msgstr "Кузатув учун белгиланг" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Кенглик" + +msgid "Longitude" +msgstr "" + +msgid "Edit" +msgstr "Таҳрирлаш" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Координаталар" + +msgid "Delete polygon" +msgstr "Полигон (кўпбурчак) ни ўчириб ташлаш" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "Ҳудудни белгиланг" + msgid "Enrollment date" msgstr "Қайд этилган сана" @@ -1199,6 +1229,12 @@ msgstr " {{date}}да охирги марта янгиланган" msgid "Cancelled" msgstr "Бекор қилинди" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1322,9 +1358,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "Таҳрирлаш" - msgid "tracked entity instance" msgstr "кузатилаётган объект намунаси" @@ -1572,12 +1605,6 @@ msgstr "Шу вақтгача" msgid "Page {{currentPage}}" msgstr "{{currentPage}} саҳифаси" -msgid "Delete polygon" -msgstr "Полигон (кўпбурчак) ни ўчириб ташлаш" - -msgid "Set area" -msgstr "Ҳудудни белгиланг" - msgid "Area on map saved" msgstr "" From fad338ddac06ca6d984ef40a5be3a562f1611197 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Sun, 26 Nov 2023 01:44:31 +0000 Subject: [PATCH 02/32] chore(release): cut 100.45.1 [skip release] ## [100.45.1](https://github.com/dhis2/capture-app/compare/v100.45.0...v100.45.1) (2023-11-26) ### Bug Fixes * **translations:** sync translations from transifex (master) ([8f28703](https://github.com/dhis2/capture-app/commit/8f28703ae8b56cfee283ec1ce0ec2b13dfd91e30)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a096db949f..364f1d18d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [100.45.1](https://github.com/dhis2/capture-app/compare/v100.45.0...v100.45.1) (2023-11-26) + + +### Bug Fixes + +* **translations:** sync translations from transifex (master) ([8f28703](https://github.com/dhis2/capture-app/commit/8f28703ae8b56cfee283ec1ce0ec2b13dfd91e30)) + # [100.45.0](https://github.com/dhis2/capture-app/compare/v100.44.7...v100.45.0) (2023-11-20) diff --git a/package.json b/package.json index 05175c3689..70d4742f93 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.45.0", + "version": "100.45.1", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.45.0", + "@dhis2/rules-engine-javascript": "100.45.1", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index dc15c3fc58..017039b19c 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.45.0", + "version": "100.45.1", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From 2dbca1efe36ed0e166d4aea803505c30c79cb35d Mon Sep 17 00:00:00 2001 From: eirikhaugstulen Date: Wed, 29 Nov 2023 13:26:44 +0100 Subject: [PATCH 03/32] fix: [DHIS2-15693] Rules not triggered on program update (#3472) --- .../EnrollmentRegistrationEntry/hooks/useLifecycle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useLifecycle.js b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useLifecycle.js index 4a84d7ccb7..a9b0eda796 100644 --- a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useLifecycle.js +++ b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useLifecycle.js @@ -45,7 +45,7 @@ export const useLifecycle = ( }); useEffect(() => { dataEntryReadyRef.current = false; - }, [teiId]); + }, [teiId, selectedScopeId]); useEffect(() => { if ( From 9e60cf78c7205423b2f0aa9ccb30909dd2e049fa Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Wed, 29 Nov 2023 12:33:21 +0000 Subject: [PATCH 04/32] chore(release): cut 100.45.2 [skip release] ## [100.45.2](https://github.com/dhis2/capture-app/compare/v100.45.1...v100.45.2) (2023-11-29) ### Bug Fixes * [DHIS2-15693] Rules not triggered on program update ([#3472](https://github.com/dhis2/capture-app/issues/3472)) ([2dbca1e](https://github.com/dhis2/capture-app/commit/2dbca1efe36ed0e166d4aea803505c30c79cb35d)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 364f1d18d5..a28036713d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [100.45.2](https://github.com/dhis2/capture-app/compare/v100.45.1...v100.45.2) (2023-11-29) + + +### Bug Fixes + +* [DHIS2-15693] Rules not triggered on program update ([#3472](https://github.com/dhis2/capture-app/issues/3472)) ([2dbca1e](https://github.com/dhis2/capture-app/commit/2dbca1efe36ed0e166d4aea803505c30c79cb35d)) + ## [100.45.1](https://github.com/dhis2/capture-app/compare/v100.45.0...v100.45.1) (2023-11-26) diff --git a/package.json b/package.json index 70d4742f93..a3a3e55966 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.45.1", + "version": "100.45.2", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.45.1", + "@dhis2/rules-engine-javascript": "100.45.2", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index 017039b19c..360a957889 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.45.1", + "version": "100.45.2", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From 2404fca8085965e699ae518cfe816f2f3d38dea7 Mon Sep 17 00:00:00 2001 From: eirikhaugstulen Date: Thu, 30 Nov 2023 13:20:00 +0100 Subject: [PATCH 05/32] feat: [DHIS2-14275] Support custom icons (#3473) --- cypress/e2e/MainPage.feature | 12 ++++++++++++ cypress/e2e/MainPage/index.js | 12 ++++++++++++ .../capture-core-utils/featuresSupport/support.js | 2 ++ .../NonBundledDhis2Icon.component.js | 11 +++++++++-- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/MainPage.feature b/cypress/e2e/MainPage.feature index 70a5430db6..980d9fd1e2 100644 --- a/cypress/e2e/MainPage.feature +++ b/cypress/e2e/MainPage.feature @@ -42,3 +42,15 @@ Feature: User interacts with Main page Then you see the opt out component for Child Programme When you opt out to use the new enrollment Dashboard for Child Programme Then you see the opt in component for Child Programme + + @v<41 + Scenario: The icon is rendered as an svg + Given you are in the main page with no selections made + When you select Child Programme + Then the icon is rendered as an svg + + @v>=41 + Scenario: The icon is rendered as a custom icon + Given you are in the main page with no selections made + When you select Child Programme + Then the icon is rendered as a custom icon diff --git a/cypress/e2e/MainPage/index.js b/cypress/e2e/MainPage/index.js index f004659122..6090ac6fb5 100644 --- a/cypress/e2e/MainPage/index.js +++ b/cypress/e2e/MainPage/index.js @@ -20,6 +20,18 @@ And('you can load the view with the name Events assigned to me', () => { }); }); +Then('the icon is rendered as a custom icon', () => { + cy.get('[alt="child_program_positive"]') + .invoke('attr', 'src') + .should('match', /\/icons\/child_program_positive\/icon$/); +}); + +Then('the icon is rendered as an svg', () => { + cy.get('[alt="child_program_positive"]') + .invoke('attr', 'src') + .should('match', /\/icons\/child_program_positive\/icon.svg$/); +}); + Then('the TEI working list is displayed', () => { cy.get('[data-test="tei-working-lists"]').within(() => { cy.contains('Rows per page').should('exist'); diff --git a/src/core_modules/capture-core-utils/featuresSupport/support.js b/src/core_modules/capture-core-utils/featuresSupport/support.js index 0b31bf6dd9..207c929c21 100644 --- a/src/core_modules/capture-core-utils/featuresSupport/support.js +++ b/src/core_modules/capture-core-utils/featuresSupport/support.js @@ -2,12 +2,14 @@ export const FEATURES = Object.freeze({ programStageWorkingList: 'programStageWorkingList', storeProgramStageWorkingList: 'storeProgramStageWorkingList', + customIcons: 'customIcons', }); // The first minor version that supports the feature const MINOR_VERSION_SUPPORT = Object.freeze({ [FEATURES.programStageWorkingList]: 39, [FEATURES.storeProgramStageWorkingList]: 40, + [FEATURES.customIcons]: 41, }); export const hasAPISupportForFeature = (minorVersion: string, featureName: string) => diff --git a/src/core_modules/capture-core/components/NonBundledDhis2Icon/NonBundledDhis2Icon.component.js b/src/core_modules/capture-core/components/NonBundledDhis2Icon/NonBundledDhis2Icon.component.js index b16ac14c1e..c6dc0002eb 100644 --- a/src/core_modules/capture-core/components/NonBundledDhis2Icon/NonBundledDhis2Icon.component.js +++ b/src/core_modules/capture-core/components/NonBundledDhis2Icon/NonBundledDhis2Icon.component.js @@ -1,13 +1,20 @@ // @flow import React from 'react'; import { useConfig } from '@dhis2/app-runtime'; -import { buildUrl } from 'capture-core-utils'; +import { buildUrl, FEATURES, useFeature } from 'capture-core-utils'; import { NonBundledIcon } from 'capture-ui'; import type { Props } from './nonBundledDhis2Icon.types'; export const NonBundledDhis2Icon = ({ name, alternativeText = name, ...passOnProps }: Props) => { + const supportCustomIcons = useFeature(FEATURES.customIcons); const { baseUrl, apiVersion } = useConfig(); - const source = name && buildUrl(baseUrl, `api/${apiVersion}/icons/${name}/icon.svg`); + let source; + + if (name) { + source = buildUrl(baseUrl, `api/${apiVersion}/icons/${name}/icon`); + // Append .svg to source if supportCustomIcons is false (feature flag v41) + source = supportCustomIcons ? source : `${source}.svg`; + } return ( Date: Thu, 30 Nov 2023 12:31:48 +0000 Subject: [PATCH 06/32] chore(release): cut 100.46.0 [skip release] # [100.46.0](https://github.com/dhis2/capture-app/compare/v100.45.2...v100.46.0) (2023-11-30) ### Features * [DHIS2-14275] Support custom icons ([#3473](https://github.com/dhis2/capture-app/issues/3473)) ([2404fca](https://github.com/dhis2/capture-app/commit/2404fca8085965e699ae518cfe816f2f3d38dea7)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a28036713d..97013b7aa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [100.46.0](https://github.com/dhis2/capture-app/compare/v100.45.2...v100.46.0) (2023-11-30) + + +### Features + +* [DHIS2-14275] Support custom icons ([#3473](https://github.com/dhis2/capture-app/issues/3473)) ([2404fca](https://github.com/dhis2/capture-app/commit/2404fca8085965e699ae518cfe816f2f3d38dea7)) + ## [100.45.2](https://github.com/dhis2/capture-app/compare/v100.45.1...v100.45.2) (2023-11-29) diff --git a/package.json b/package.json index a3a3e55966..cd12b9b935 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.45.2", + "version": "100.46.0", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.45.2", + "@dhis2/rules-engine-javascript": "100.46.0", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index 360a957889..b53e6943e0 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.45.2", + "version": "100.46.0", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From a24bb2723f06cd4a3ca87bbbb22977b097377b3c Mon Sep 17 00:00:00 2001 From: Tony Valle <79843014+superskip@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:46:51 +0100 Subject: [PATCH 07/32] fix: [DHIS2-15686] fix program rule variables for edit profile mode (#3463) --- .../WidgetProfile/DataEntry/ProgramRules/rulesContainer.js | 3 ++- .../components/WidgetProfile/DataEntry/hooks/useEvents.js | 6 +++--- .../WidgetProfile/DataEntry/hooks/useLifecycle.js | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/ProgramRules/rulesContainer.js b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/ProgramRules/rulesContainer.js index bb75e2a61d..554648322a 100644 --- a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/ProgramRules/rulesContainer.js +++ b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/ProgramRules/rulesContainer.js @@ -1,12 +1,13 @@ // @flow import type { ProgramRulesContainer } from '@dhis2/rules-engine-javascript'; -import { getTrackedEntityAttributeId, getProgramId, getProgramRuleActions, getProgramStageId } from '../helpers'; +import { getTrackedEntityAttributeId, getDataElementId, getProgramId, getProgramRuleActions, getProgramStageId } from '../helpers'; import { getRulesAndVariablesFromProgramIndicators } from '../../../../metaDataMemoryStoreBuilders/programs/getRulesAndVariablesFromIndicators'; const addProgramVariables = (program, programRuleVariables) => { program.programRuleVariables = programRuleVariables.map(programRulesVariable => ({ ...programRulesVariable, programId: getProgramId(programRulesVariable), + dataElementId: getDataElementId(programRulesVariable), trackedEntityAttributeId: getTrackedEntityAttributeId(programRulesVariable), })); }; diff --git a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/hooks/useEvents.js b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/hooks/useEvents.js index 0c900af9a4..6e606a08d4 100644 --- a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/hooks/useEvents.js +++ b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/hooks/useEvents.js @@ -10,7 +10,7 @@ const getClientFormattedDataValuesAsObject = (dataValues, elementsById) => dataValues.reduce((acc, { dataElement: id, value }) => { const dataElement = elementsById[id]; if (dataElement) { - acc[id] = convertValue(value, elementsById[id].type); + acc[id] = convertValue(value, dataElement.valueType); } return acc; }, {}); @@ -39,8 +39,8 @@ export const useEvents = (enrollment: any, elementsById: Array) => { enrollmentId: event.enrollment, enrollmentStatus: event.enrollmentStatus, status: event.status, - eventDate: convertDate(event.eventDate), - dueDate: convertDate(event.dueDate), + occurredAt: convertDate(event.occurredAt), + scheduledAt: convertDate(event.scheduledAt), ...getClientFormattedDataValuesAsObject(event.dataValues, elementsById), })), [elementsById, enrollment, orgUnitNames], diff --git a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/hooks/useLifecycle.js b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/hooks/useLifecycle.js index ce75b815f8..c60464a921 100644 --- a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/hooks/useLifecycle.js +++ b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/hooks/useLifecycle.js @@ -49,7 +49,7 @@ export const useLifecycle = ({ const state = useSelector(stateArg => stateArg); const enrollment = useSelector(({ enrollmentDomain }) => enrollmentDomain?.enrollment); const dataElements: DataElements = useDataElements(programAPI); - const otherEvents = useEvents(enrollment, programAPI); + const otherEvents = useEvents(enrollment, dataElements); const orgUnit: ?OrgUnit = useOrganisationUnit(orgUnitId).orgUnit; const rulesContainer: ProgramRulesContainer = useRulesContainer(programAPI); const formFoundation: RenderFoundation = useFormFoundation(programAPI); From 47a95b2989880af8264f63409b57b9bf7043776e Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Thu, 30 Nov 2023 13:02:09 +0000 Subject: [PATCH 08/32] chore(release): cut 100.46.1 [skip release] ## [100.46.1](https://github.com/dhis2/capture-app/compare/v100.46.0...v100.46.1) (2023-11-30) ### Bug Fixes * [DHIS2-15686] fix program rule variables for edit profile mode ([#3463](https://github.com/dhis2/capture-app/issues/3463)) ([a24bb27](https://github.com/dhis2/capture-app/commit/a24bb2723f06cd4a3ca87bbbb22977b097377b3c)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97013b7aa0..7b603a0b17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [100.46.1](https://github.com/dhis2/capture-app/compare/v100.46.0...v100.46.1) (2023-11-30) + + +### Bug Fixes + +* [DHIS2-15686] fix program rule variables for edit profile mode ([#3463](https://github.com/dhis2/capture-app/issues/3463)) ([a24bb27](https://github.com/dhis2/capture-app/commit/a24bb2723f06cd4a3ca87bbbb22977b097377b3c)) + # [100.46.0](https://github.com/dhis2/capture-app/compare/v100.45.2...v100.46.0) (2023-11-30) diff --git a/package.json b/package.json index cd12b9b935..4648cadedc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.46.0", + "version": "100.46.1", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.46.0", + "@dhis2/rules-engine-javascript": "100.46.1", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index b53e6943e0..ff1415cd4f 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.46.0", + "version": "100.46.1", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From 620b00832da7c4951d6e905b40317dd0acca0aa6 Mon Sep 17 00:00:00 2001 From: eirikhaugstulen Date: Fri, 1 Dec 2023 08:07:29 +0100 Subject: [PATCH 09/32] feat: [DHIS2-16123] Add inheritable TEAs to Relationships (#3464) --- .../hooks/useFormValues.js | 10 ++- .../TeiRegistrationEntry.container.js | 40 +++++++++-- .../TeiRegistrationEntry.types.js | 2 + .../hooks/useFormValuesFromSearchTerms.js | 31 +++++--- .../SingleOrgUnitSelectField.component.js | 6 +- .../components/Pages/New/NewPage.types.js | 3 +- .../RegistrationDataEntry.types.js | 4 +- .../DataEntryEnrollment.component.js | 2 + .../Enrollment/dataEntryEnrollment.types.js | 2 + .../RegisterTeiDataEntry.component.js | 8 ++- .../DataEntryTrackedEntityInstance.js | 2 + .../dataEntryTrackedEntityInstance.types.js | 2 + .../RegisterTei/RegisterTei.component.js | 2 + .../RegisterTei/RegisterTei.container.js | 12 ++++ .../RegisterTei/RegisterTei.types.js | 4 ++ ...kedEntityRelationshipsWrapper.component.js | 1 + .../useInheritedAttributeValues.js | 70 +++++++++++++++++++ .../metaData/DataElement/DataElement.js | 9 +++ .../factory/enrollment/DataElementFactory.js | 1 + .../TrackedEntityType/DataElementFactory.js | 1 + .../storeTrackedEntityAttributes.js | 2 +- .../storageControllers/cache.types.js | 1 + .../query/useApiDataQuery.js | 2 +- 23 files changed, 189 insertions(+), 28 deletions(-) create mode 100644 src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/useInheritedAttributeValues.js diff --git a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues.js b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues.js index 1431a10e23..679d973ecb 100644 --- a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues.js +++ b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues.js @@ -8,6 +8,7 @@ import type { RenderFoundation } from '../../../../metaData'; import { convertClientToForm, convertServerToClient } from '../../../../converters'; import { subValueGetterByElementType } from './getSubValueForTei'; import type { QuerySingleResource } from '../../../../utils/api/api.types'; +import { dataElementTypes } from '../../../../metaData'; type InputProgramData = { attributes: Array<{ @@ -32,7 +33,7 @@ export type InputAttribute = { displayName: string, lastUpdated: string, value: string, - valueType: string, + valueType: $Keys, }; type InputForm = { @@ -50,7 +51,7 @@ type StaticPatternValues = { const useClientAttributesWithSubvalues = (program: InputProgramData, attributes: Array) => { const dataEngine = useDataEngine(); - const [listAttributes, setListAttributes] = useState([]); + const [listAttributes, setListAttributes] = useState(null); const getListAttributes = useCallback(async () => { if (program && attributes) { @@ -139,8 +140,6 @@ export const useFormValues = ({ program, trackedEntityInstanceAttributes, orgUni const formValuesReadyRef = useRef(false); const [formValues, setFormValues] = useState({}); const [clientValues, setClientValues] = useState({}); - const areAttributesWithSubvaluesReady = - (teiId && clientAttributesWithSubvalues.length > 0) || (!teiId && clientAttributesWithSubvalues.length === 0); useEffect(() => { formValuesReadyRef.current = false; @@ -152,7 +151,7 @@ export const useFormValues = ({ program, trackedEntityInstanceAttributes, orgUni formFoundation && Object.entries(formFoundation).length > 0 && formValuesReadyRef.current === false && - areAttributesWithSubvaluesReady + !!clientAttributesWithSubvalues ) { const staticPatternValues = { orgUnitCode: orgUnit.code }; const querySingleResource = makeQuerySingleResource(dataEngine.query.bind(dataEngine)); @@ -172,7 +171,6 @@ export const useFormValues = ({ program, trackedEntityInstanceAttributes, orgUni clientAttributesWithSubvalues, formValuesReadyRef, orgUnit, - areAttributesWithSubvaluesReady, searchTerms, dataEngine, ]); diff --git a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.container.js b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.container.js index 4c3b8badab..7d017181b9 100644 --- a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.container.js +++ b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.container.js @@ -11,19 +11,37 @@ import { useFormValuesFromSearchTerms } from './hooks/useFormValuesFromSearchTer import { dataEntryHasChanges } from '../../DataEntry/common/dataEntryHasChanges'; import { useMetadataForRegistrationForm } from '../common/TEIAndEnrollment/useMetadataForRegistrationForm'; import { useBuildTeiPayload } from './hooks/useBuildTeiPayload'; +import type { InputAttribute } from '../EnrollmentRegistrationEntry/hooks/useFormValues'; -const useInitialiseTeiRegistration = (selectedScopeId, dataEntryId, orgUnitId) => { +type Props = { + selectedScopeId: string, + dataEntryId: string, + orgUnitId: string, + inheritedAttributes: ?Array, +} +const useInitialiseTeiRegistration = ({ + selectedScopeId, + dataEntryId, + orgUnitId, + inheritedAttributes, +}: Props) => { const dispatch = useDispatch(); const { scopeType, trackedEntityName } = useScopeInfo(selectedScopeId); const { formId, formFoundation } = useMetadataForRegistrationForm({ selectedScopeId }); - const formValues = useFormValuesFromSearchTerms(); + const formValues = useFormValuesFromSearchTerms({ inheritedAttributes }); const registrationFormReady = !!formId; useEffect(() => { if (registrationFormReady && scopeType === scopeTypes.TRACKED_ENTITY_TYPE) { dispatch( startNewTeiDataEntryInitialisation( - { selectedOrgUnitId: orgUnitId, selectedScopeId, dataEntryId, formFoundation, formValues }, + { + selectedOrgUnitId: orgUnitId, + selectedScopeId, + dataEntryId, + formFoundation, + formValues, + }, )); } }, [ @@ -43,8 +61,20 @@ const useInitialiseTeiRegistration = (selectedScopeId, dataEntryId, orgUnitId) = }; -export const TeiRegistrationEntry: ComponentType = ({ selectedScopeId, id, orgUnitId, onSave, ...rest }) => { - const { trackedEntityName } = useInitialiseTeiRegistration(selectedScopeId, id, orgUnitId); +export const TeiRegistrationEntry: ComponentType = ({ + selectedScopeId, + id, + orgUnitId, + onSave, + inheritedAttributes, + ...rest +}) => { + const { trackedEntityName } = useInitialiseTeiRegistration({ + selectedScopeId, + dataEntryId: id, + orgUnitId, + inheritedAttributes, + }); const ready = useSelector(({ dataEntries }) => (!!dataEntries[id])); const dataEntry = useSelector(({ dataEntries }) => (dataEntries[id])); const { diff --git a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js index 43afd9adc8..33f32eabf8 100644 --- a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js +++ b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js @@ -6,6 +6,7 @@ import type { ExistingUniqueValueDialogActionsComponent } from '../withErrorMess import type { TeiPayload, } from '../../Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types'; +import type { InputAttribute } from '../EnrollmentRegistrationEntry/hooks/useFormValues'; export type OwnProps = $ReadOnly<{| id: string, @@ -16,6 +17,7 @@ export type OwnProps = $ReadOnly<{| onSave: (TeiPayload) => void, duplicatesReviewPageSize: number, isSavingInProgress?: boolean, + inheritedAttributes?: Array, renderDuplicatesCardActions?: RenderCustomCardActions, renderDuplicatesDialogActions?: (onCancel: () => void, onSave: (TeiPayload) => void) => Node, ExistingUniqueValueDialogActions: ExistingUniqueValueDialogActionsComponent, diff --git a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/hooks/useFormValuesFromSearchTerms.js b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/hooks/useFormValuesFromSearchTerms.js index 87bdf7fa98..42c6fbff54 100644 --- a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/hooks/useFormValuesFromSearchTerms.js +++ b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/hooks/useFormValuesFromSearchTerms.js @@ -1,19 +1,32 @@ // @flow -import { useEffect, useState } from 'react'; +import { useMemo } from 'react'; import { useSelector } from 'react-redux'; import { convertClientToForm } from '../../../../converters'; +import type { InputAttribute } from '../../EnrollmentRegistrationEntry/hooks/useFormValues'; +type Props = { + inheritedAttributes: ?Array, +}; -export const useFormValuesFromSearchTerms = () => { +export const useFormValuesFromSearchTerms = ({ inheritedAttributes }: Props) => { const searchTerms = useSelector(({ searchDomain }) => searchDomain.currentSearchInfo.currentSearchTerms); - const [formValues, setFormValues] = useState(); - useEffect(() => { + + return useMemo(() => { + if (inheritedAttributes) { + return inheritedAttributes + ?.reduce((acc, item) => { + acc[item.attribute] = convertClientToForm(item.value, item.valueType); + return acc; + }, {}); + } if (searchTerms) { - const searchFormValues = searchTerms - ?.reduce((acc, item) => ({ ...acc, [item.id]: convertClientToForm(item.value, item.type) }), {}); - setFormValues(searchFormValues); + return searchTerms + ?.reduce((acc, item) => { + acc[item.id] = convertClientToForm(item.value, item.type); + return acc; + }, {}); } - }, [searchTerms]); - return formValues; + return null; + }, [inheritedAttributes, searchTerms]); }; diff --git a/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js b/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js index 6c252f087b..7946993a79 100644 --- a/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js +++ b/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js @@ -13,7 +13,7 @@ const getStyles = () => ({ type OrgUnitValue = { id: string, - name: string, + displayName: string, path: string, } @@ -44,7 +44,7 @@ class SingleOrgUnitSelectFieldPlain extends React.Component { const { classes } = this.props; return (
- {selectedOrgUnit.name} + {selectedOrgUnit.displayName}
); } @@ -52,7 +52,7 @@ class SingleOrgUnitSelectFieldPlain extends React.Component { onSelectOrgUnit = (orgUnit: Object) => { this.props.onBlur({ id: orgUnit.id, - name: orgUnit.displayName, + displayName: orgUnit.displayName, path: orgUnit.path, }); } diff --git a/src/core_modules/capture-core/components/Pages/New/NewPage.types.js b/src/core_modules/capture-core/components/Pages/New/NewPage.types.js index 899367152f..f9357422d7 100644 --- a/src/core_modules/capture-core/components/Pages/New/NewPage.types.js +++ b/src/core_modules/capture-core/components/Pages/New/NewPage.types.js @@ -1,5 +1,6 @@ // @flow import { typeof newPageStatuses } from './NewPage.constants'; +import { dataElementTypes } from '../../../metaData'; type ProgramCategories = Array<{|name: string, id: string|}> @@ -10,7 +11,7 @@ type InputAttribute = { displayName: string, lastUpdated: string, value: string, - valueType: string, + valueType: $Keys, }; export type ContainerProps = $ReadOnly<{| diff --git a/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js b/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js index 79a07ea96e..22e908fb66 100644 --- a/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js +++ b/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js @@ -1,5 +1,7 @@ // @flow +import { dataElementTypes } from '../../../../metaData'; + type InputAttribute = { attribute: string, code: string, @@ -7,7 +9,7 @@ type InputAttribute = { displayName: string, lastUpdated: string, value: string, - valueType: string, + valueType: $Keys, }; export type OwnProps = $ReadOnly<{| diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js index 2dbf0c7a20..25b215eed7 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js @@ -12,6 +12,7 @@ const NewEnrollmentRelationshipPlain = theme, onSave, programId, + inheritedAttributes, orgUnitId, duplicatesReviewPageSize, renderDuplicatesDialogActions, @@ -35,6 +36,7 @@ const NewEnrollmentRelationshipPlain = renderDuplicatesDialogActions={renderDuplicatesDialogActions} renderDuplicatesCardActions={renderDuplicatesCardActions} ExistingUniqueValueDialogActions={ExistingUniqueValueDialogActions} + trackedEntityInstanceAttributes={inheritedAttributes} /> ); }; diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js index de3f6cee6f..3b32b17d35 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js @@ -6,11 +6,13 @@ import type { SaveForEnrollmentAndTeiRegistration, ExistingUniqueValueDialogActionsComponent, } from '../../../../../../DataEntries'; +import type { InputAttribute } from '../../../../../../DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues'; export type Props = {| theme: Theme, programId: string, orgUnitId: string, + inheritedAttributes: Array, enrollmentMetadata?: Enrollment, onSave: SaveForEnrollmentAndTeiRegistration, duplicatesReviewPageSize: number, diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/RegisterTeiDataEntry.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/RegisterTeiDataEntry.component.js index 292a1d1530..940aa904fd 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/RegisterTeiDataEntry.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/RegisterTeiDataEntry.component.js @@ -12,7 +12,13 @@ type Props = { export class RegisterTeiDataEntryComponent extends React.Component { render() { - const { showDataEntry, programId, onSaveWithoutEnrollment, onSaveWithEnrollment, ...passOnProps } = this.props; + const { + showDataEntry, + programId, + onSaveWithoutEnrollment, + onSaveWithEnrollment, + ...passOnProps + } = this.props; if (!showDataEntry) { return null; diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js index c455e3616d..20579fc2db 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js @@ -14,6 +14,7 @@ const RelationshipTrackedEntityInstancePlain = theme, onSave, trackedEntityTypeId, + inheritedAttributes, duplicatesReviewPageSize, renderDuplicatesDialogActions, renderDuplicatesCardActions, @@ -36,6 +37,7 @@ const RelationshipTrackedEntityInstancePlain = orgUnitId={orgUnitId} teiRegistrationMetadata={teiRegistrationMetadata} selectedScopeId={teiRegistrationMetadata.form.id} + inheritedAttributes={inheritedAttributes} saveButtonText={i18n.t('Save new {{trackedEntityTypeName}} and link', { trackedEntityTypeName: trackedEntityTypeNameLC, interpolation: { escapeValue: false }, })} diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js index b4f9617052..4fcec10567 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js @@ -5,6 +5,7 @@ import type { RenderCustomCardActions } from '../../../../../../CardList'; import type { ExistingUniqueValueDialogActionsComponent, } from '../../../../../../DataEntries'; +import type { InputAttribute } from '../../../../../../DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues'; export type TeiPayload = {| trackedEntity: string, @@ -23,6 +24,7 @@ export type Props = {| trackedEntityTypeId: string, onSave: TeiPayload => void, teiRegistrationMetadata?: TeiRegistration, + inheritedAttributes: Array, duplicatesReviewPageSize: number, renderDuplicatesCardActions?: RenderCustomCardActions, renderDuplicatesDialogActions?: (onCancel: () => void, onSave: (TeiPayload) => void) => Node, diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js index 9a9a7070af..c22abb0c0e 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js @@ -64,6 +64,7 @@ const RegisterTeiPlain = ({ trackedEntityName, trackedEntityTypeId, selectedScopeId, + inheritedAttributes, classes, }: ComponentProps) => { const { resultsPageSize } = useContext(ResultsPageSizeContext); @@ -110,6 +111,7 @@ const RegisterTeiPlain = ({ renderDuplicatesDialogActions={renderDuplicatesDialogActions} renderDuplicatesCardActions={renderDuplicatesCardActions} ExistingUniqueValueDialogActions={ExistingUniqueValueDialogActions} + inheritedAttributes={inheritedAttributes} /> { @@ -16,6 +18,15 @@ export const RegisterTei = ({ const error = useSelector(({ newRelationshipRegisterTei }) => (newRelationshipRegisterTei.error)); const selectedScopeId = suggestedProgramId || trackedEntityTypeId; const { trackedEntityName } = useScopeInfo(selectedScopeId); + const { inheritedAttributes, isLoading: isLoadingAttributes } = useInheritedAttributeValues({ + teiId, + trackedEntityTypeId, + programId: suggestedProgramId, + }); + + if (isLoadingAttributes) { + return null; + } return ( ); }; diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.types.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.types.js index 0de2b570ba..dea706722b 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.types.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.types.js @@ -1,4 +1,6 @@ // @flow +import type { InputAttribute } from '../../../../DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues'; + export type SharedProps = {| onLink: (teiId: string, values: Object) => void, onGetUnsavedAttributeValues?: ?Function, @@ -7,6 +9,7 @@ export type SharedProps = {| export type ContainerProps = {| suggestedProgramId: string, + teiId: string, onSave: (teiPayload: Object) => void, ...SharedProps, |}; @@ -16,6 +19,7 @@ export type ComponentProps = {| error: string, dataEntryId: string, trackedEntityName: ?string, + inheritedAttributes: Array, onSaveWithEnrollment: () => void, onSaveWithoutEnrollment: () => void, ...SharedProps, diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js index df27fb1125..135dafe53f 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js @@ -76,6 +76,7 @@ export const TrackedEntityRelationshipsWrapper = ({ suggestedProgramId={suggestedProgramId} onLink={onLinkToTrackedEntityFromSearch} onSave={onLinkToTrackedEntityFromRegistration} + teiId={teiId} onGetUnsavedAttributeValues={() => console.log('get unsaved')} trackedEntityTypeId={selectedTrackedEntityTypeId} /> diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/useInheritedAttributeValues.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/useInheritedAttributeValues.js new file mode 100644 index 0000000000..8c526525dd --- /dev/null +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/useInheritedAttributeValues.js @@ -0,0 +1,70 @@ +// @flow +import { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import type { InputAttribute } from '../../../DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues'; +import { useApiDataQuery } from '../../../../utils/reactQueryHelpers'; +import { + getProgramFromProgramIdThrowIfNotFound, + getTrackedEntityTypeThrowIfNotFound, + TrackerProgram, +} from '../../../../metaData'; + +type Props = { + teiId: string, + trackedEntityTypeId: string, +}; + +type Return = { + inheritedAttributes: Array, + isLoading: boolean, +}; +export const useInheritedAttributeValues = ({ teiId, trackedEntityTypeId }: Props): Return => { + const programId = useSelector(({ newRelationshipRegisterTei }) => newRelationshipRegisterTei.programId); + const inheritedAttributeIds = useMemo(() => { + const attributeIds = new Set(); + + if (programId) { + const program = getProgramFromProgramIdThrowIfNotFound(programId); + if (program instanceof TrackerProgram) { + program.attributes.forEach((attribute) => { + if (attribute.inherit) { + attributeIds.add(attribute.id); + } + }); + } + return attributeIds; + } + + const trackedEntityType = getTrackedEntityTypeThrowIfNotFound(trackedEntityTypeId); + trackedEntityType.attributes.forEach((attribute) => { + if (attribute.inherit) { + attributeIds.add(attribute.id); + } + }); + return attributeIds; + }, [programId, trackedEntityTypeId]); + + + const { data, isLoading } = useApiDataQuery( + ['inheritedAttributeValues', teiId, programId], + { + resource: 'tracker/trackedEntities', + id: teiId, + params: { + fields: ['attributes'], + program: programId, + }, + }, { + enabled: !!teiId, + select: (response) => { + const attributes = response.attributes || []; + return attributes + .filter(attribute => inheritedAttributeIds.has(attribute.attribute)); + }, + }); + + return { + inheritedAttributes: data ?? [], + isLoading, + }; +}; diff --git a/src/core_modules/capture-core/metaData/DataElement/DataElement.js b/src/core_modules/capture-core/metaData/DataElement/DataElement.js index 5555d4842e..78fe1d959a 100644 --- a/src/core_modules/capture-core/metaData/DataElement/DataElement.js +++ b/src/core_modules/capture-core/metaData/DataElement/DataElement.js @@ -35,6 +35,7 @@ export class DataElement { _displayInReports: boolean; _icon: Icon | void; _unique: ?Unique; + _inherit: boolean; _searchable: ?boolean; _url: ?string; _attributeValues: Array @@ -157,6 +158,14 @@ export class DataElement { return this._unique; } + get inherit(): boolean { + return this._inherit; + } + + set inherit(value: boolean) { + this._inherit = value; + } + set searchable(searchable: boolean) { this._searchable = searchable; } diff --git a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js index 18e56e1869..27d1222735 100644 --- a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js +++ b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js @@ -164,6 +164,7 @@ export class DataElementFactory { dataElement.compulsory = cachedProgramTrackedEntityAttribute.mandatory; dataElement.code = cachedTrackedEntityAttribute.code; dataElement.attributeValues = cachedTrackedEntityAttribute.attributeValues; + dataElement.inherit = cachedTrackedEntityAttribute.inherit; dataElement.name = this._getAttributeTranslation( cachedTrackedEntityAttribute.translations, diff --git a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js index bc27da80ed..723d148d3c 100644 --- a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js +++ b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js @@ -112,6 +112,7 @@ export class DataElementFactory { cachedAttribute.translations, DataElementFactory.translationPropertyNames.DESCRIPTION) || cachedAttribute.description; o.displayInForms = true; + o.inherit = cachedAttribute.inherit; o.displayInReports = cachedTrackedEntityTypeAttribute.displayInList; o.disabled = false; o.type = cachedAttribute.valueType; diff --git a/src/core_modules/capture-core/metaDataStoreLoaders/trackedEntityAttributes/quickStoreOperations/storeTrackedEntityAttributes.js b/src/core_modules/capture-core/metaDataStoreLoaders/trackedEntityAttributes/quickStoreOperations/storeTrackedEntityAttributes.js index 8624bb577e..7658ff4a8b 100644 --- a/src/core_modules/capture-core/metaDataStoreLoaders/trackedEntityAttributes/quickStoreOperations/storeTrackedEntityAttributes.js +++ b/src/core_modules/capture-core/metaDataStoreLoaders/trackedEntityAttributes/quickStoreOperations/storeTrackedEntityAttributes.js @@ -7,7 +7,7 @@ export const storeTrackedEntityAttributes = (ids: Array) => { resource: 'trackedEntityAttributes', params: { fields: 'id,displayName,displayShortName,displayFormName,description,valueType,optionSetValue,unique,orgunitScope,' + - 'pattern,code,attributeValues,translations[property,locale,value],optionSet[id]', + 'pattern,code,attributeValues,inherit,translations[property,locale,value],optionSet[id]', filter: `id:in:[${ids.join(',')}]`, pageSize: ids.length, }, diff --git a/src/core_modules/capture-core/storageControllers/cache.types.js b/src/core_modules/capture-core/storageControllers/cache.types.js index 49ce4a64ca..01ba461309 100644 --- a/src/core_modules/capture-core/storageControllers/cache.types.js +++ b/src/core_modules/capture-core/storageControllers/cache.types.js @@ -26,6 +26,7 @@ export type CachedTrackedEntityAttribute = { translations: Array, valueType: string, optionSetValue: boolean, + inherit: boolean, optionSet: { id: string }, unique: ?boolean, orgunitScope: ?boolean, diff --git a/src/core_modules/capture-core/utils/reactQueryHelpers/query/useApiDataQuery.js b/src/core_modules/capture-core/utils/reactQueryHelpers/query/useApiDataQuery.js index 8505d4aaff..44b0ba996f 100644 --- a/src/core_modules/capture-core/utils/reactQueryHelpers/query/useApiDataQuery.js +++ b/src/core_modules/capture-core/utils/reactQueryHelpers/query/useApiDataQuery.js @@ -6,7 +6,7 @@ import type { Result } from './useMetadataQuery.types'; import { ReactQueryAppNamespace } from '../reactQueryHelpers.const'; export const useApiDataQuery = ( - queryKey: Array, + queryKey: Array, queryObject: ResourceQuery, queryOptions: UseQueryOptions, ): Result => { From e20fb8c551aefb0546c5973dd87940d56e3018be Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Sun, 3 Dec 2023 02:37:54 +0100 Subject: [PATCH 10/32] fix(translations): sync translations from transifex (master) Automatically merged. --- i18n/ar.po | 56 ++++-- i18n/cs.po | 42 +++- i18n/es.po | 52 +++-- i18n/es_419.po | 131 ++++++++++--- i18n/fr.po | 54 ++++-- i18n/id.po | 54 ++++-- i18n/km.po | 133 ++++++++++--- i18n/lo.po | 54 ++++-- i18n/nb.po | 52 +++-- i18n/nl.po | 48 +++-- i18n/or.po | 468 ++++++++++++++++++++++++++++++--------------- i18n/prs.po | 48 +++-- i18n/ps.po | 46 +++-- i18n/pt.po | 48 +++-- i18n/pt_BR.po | 42 +++- i18n/ru.po | 48 +++-- i18n/sv.po | 46 +++-- i18n/tg.po | 46 +++-- i18n/uk.po | 46 +++-- i18n/ur.po | 52 +++-- i18n/uz_UZ_Cyrl.po | 4 +- i18n/uz_UZ_Latn.po | 48 +++-- i18n/vi.po | 52 +++-- i18n/zh.po | 48 +++-- i18n/zh_CN.po | 46 +++-- 25 files changed, 1291 insertions(+), 473 deletions(-) diff --git a/i18n/ar.po b/i18n/ar.po index e1e1024ca7..f2f9d46408 100644 --- a/i18n/ar.po +++ b/i18n/ar.po @@ -1,16 +1,16 @@ # # Translators: # KRG HIS , 2020 -# Viktor Varland , 2023 -# Hamza Assada <7amza.it@gmail.com>, 2023 # Philip Larsen Donnelly, 2023 +# Hamza Assada <7amza.it@gmail.com>, 2023 +# Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Philip Larsen Donnelly, 2023\n" +"Last-Translator: Viktor Varland , 2023\n" "Language-Team: Arabic (https://app.transifex.com/hisp-uio/teams/100509/ar/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -533,6 +533,9 @@ msgstr "ابدأ الكتابة للبحث" msgid "suggestions could not be retrieved" msgstr "تعذر استرداد الاقتراحات" +msgid "No results found" +msgstr "لم يتم العثور على أي نتائج" + msgid "No items to display" msgstr "لا توجد عناصر للعرض" @@ -951,9 +954,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "إحتمال وجود تكرار" -msgid "No results found" -msgstr "لم يتم العثور على أي نتائج" - msgid "An error occurred loading possible duplicates" msgstr "" @@ -1154,6 +1154,33 @@ msgstr "اشر من أجل الملحق" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "خط العرض" + +msgid "Longitude" +msgstr "خط الطول" + +msgid "Edit" +msgstr "تعديل" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "الإحداثيات" + +msgid "Delete polygon" +msgstr "حذف المضلع" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "عين المساحة" + msgid "Enrollment date" msgstr "تاريخ التسجيل" @@ -1178,6 +1205,12 @@ msgstr "" msgid "Cancelled" msgstr "الملغية" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1300,9 +1333,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "تعديل" - msgid "tracked entity instance" msgstr "نموذج الكيان المتتبع" @@ -1368,7 +1398,7 @@ msgid "To open this relationship, please wait until saving is complete" msgstr "" msgid "Type" -msgstr "" +msgstr "النوع" msgid "Created date" msgstr "" @@ -1550,12 +1580,6 @@ msgstr "إلى وقت" msgid "Page {{currentPage}}" msgstr "صفحة {{currentPage}}" -msgid "Delete polygon" -msgstr "حذف المضلع" - -msgid "Set area" -msgstr "عين المساحة" - msgid "Area on map saved" msgstr "" diff --git a/i18n/cs.po b/i18n/cs.po index 171ec3d5b0..eb1fcb93e4 100644 --- a/i18n/cs.po +++ b/i18n/cs.po @@ -1191,6 +1191,33 @@ msgid "Existing dates for auto-generated events will not be updated." msgstr "" "Stávající data pro automaticky generované události nebudou aktualizována." +msgid "Latitude" +msgstr "Zeměpisná šířka" + +msgid "Longitude" +msgstr "Zeměpisná délka" + +msgid "Edit" +msgstr "Upravit" + +msgid "Set coordinates" +msgstr "Nastavit souřadnice" + +msgid "Coordinates" +msgstr "Souřadnice" + +msgid "Delete polygon" +msgstr "Smazat polygon" + +msgid "Close without saving" +msgstr "Zavřít bez uložení" + +msgid "Finish drawing before saving" +msgstr "Před uložením dokončete kreslení" + +msgid "Set area" +msgstr "Nastavit oblast" + msgid "Enrollment date" msgstr "Datum zápisu" @@ -1215,6 +1242,12 @@ msgstr "Poslední aktualizace {{date}}" msgid "Cancelled" msgstr "Zrušeno" +msgid "Add coordinates" +msgstr "Přidat souřadnice" + +msgid "Add area" +msgstr "Přidat oblast" + msgid "Comments about this enrollment" msgstr "Komentáře k tomuto zápisu" @@ -1343,9 +1376,6 @@ msgstr "Widget profilu nelze načíst. Prosím zkuste to znovu později" msgid "{{TETName}} profile" msgstr "profil {{TETName}}" -msgid "Edit" -msgstr "Upravit" - msgid "tracked entity instance" msgstr "sledovaná instance entity" @@ -1593,12 +1623,6 @@ msgstr "Na čas" msgid "Page {{currentPage}}" msgstr "Stránka {{currentPage}}" -msgid "Delete polygon" -msgstr "Smazat polygon" - -msgid "Set area" -msgstr "Nastavit oblast" - msgid "Area on map saved" msgstr "Oblast na mapě byla uložena" diff --git a/i18n/es.po b/i18n/es.po index a009f61377..67b54c1201 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -6,20 +6,20 @@ # Philip Larsen Donnelly, 2022 # Marta Vila , 2022 # Pablo Pajuelo Cabezas , 2022 -# Viktor Varland , 2023 # Alison Andrade , 2023 # Janeth Cruz, 2023 # Prabhjot Singh, 2023 # Christian Atavillos, 2023 # Enzo Nicolas Rossi , 2023 # Gabriela Rodriguez , 2023 +# Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Gabriela Rodriguez , 2023\n" +"Last-Translator: Viktor Varland , 2023\n" "Language-Team: Spanish (https://app.transifex.com/hisp-uio/teams/100509/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -557,6 +557,9 @@ msgstr "Empiece a escribir para buscar" msgid "suggestions could not be retrieved" msgstr "No se pudieron recuperar las sugerencias" +msgid "No results found" +msgstr "No results found" + msgid "No items to display" msgstr "No hay elementos para mostrar" @@ -1004,9 +1007,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "Posibles duplicados encontrados" -msgid "No results found" -msgstr "No results found" - msgid "An error occurred loading possible duplicates" msgstr "Se produjo un error al cargar posibles duplicados" @@ -1226,6 +1226,33 @@ msgstr "Marcar para seguimiento" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Latitud" + +msgid "Longitude" +msgstr "Longitud" + +msgid "Edit" +msgstr "Editar" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Coordenadas" + +msgid "Delete polygon" +msgstr "Eliminar polígono" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "Establecer área" + msgid "Enrollment date" msgstr "Fecha de inscripción" @@ -1252,6 +1279,12 @@ msgstr "Última actualización {{date}}" msgid "Cancelled" msgstr "Cancelar" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "Comentarios sobre esta inscripción" @@ -1388,9 +1421,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "Perfil de {{TETName}} " -msgid "Edit" -msgstr "Editar" - msgid "tracked entity instance" msgstr "instancia de entidad rastreada" @@ -1642,12 +1672,6 @@ msgstr "Hasta la hora" msgid "Page {{currentPage}}" msgstr "Página {{currentPage}}" -msgid "Delete polygon" -msgstr "Eliminar polígono" - -msgid "Set area" -msgstr "Establecer área" - msgid "Area on map saved" msgstr "Área en el mapa guardada" diff --git a/i18n/es_419.po b/i18n/es_419.po index 42247a9fcb..9e781ff26a 100644 --- a/i18n/es_419.po +++ b/i18n/es_419.po @@ -1,14 +1,14 @@ # # Translators: -# Jaime Bosque , 2023 # Enzo Nicolas Rossi , 2023 +# Jaime Bosque , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-09-04T07:07:59.195Z\n" +"POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Enzo Nicolas Rossi , 2023\n" +"Last-Translator: Jaime Bosque , 2023\n" "Language-Team: Spanish (Latin America) (https://app.transifex.com/hisp-uio/teams/100509/es_419/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -160,6 +160,15 @@ msgstr "Coordenadas" msgid "Enrollment" msgstr "Inscripción" +msgid "Complete event" +msgstr "Evento completo" + +msgid "{{ stageName }} - Basic info" +msgstr "" + +msgid "{{ stageName }} - Status" +msgstr "" + msgid "Please select {{categoryName}}" msgstr "" @@ -182,15 +191,18 @@ msgstr "" "Error de metadatos. Un administrador deberá ver el registro de auditoría " "para más detalles" +msgid "{{ stageName }} - Details" +msgstr "" + +msgid "{{ stageName }} - {{ sectionName }}" +msgstr "" + msgid "Assigned user" msgstr "Usuario asignado" msgid "Search for user" msgstr "Buscar usuario" -msgid "Complete event" -msgstr "Evento completo" - msgid "Basic info" msgstr " " @@ -532,6 +544,9 @@ msgstr "Empiece a escribir para buscar" msgid "suggestions could not be retrieved" msgstr "no se pudieron cargar las sugerencias" +msgid "No results found" +msgstr "" + msgid "No items to display" msgstr "No hay elementos para mostrar" @@ -947,10 +962,19 @@ msgstr "" msgid "Organisation unit could not be loaded" msgstr "" -msgid "Possible duplicates found" +msgid "Selected program" msgstr "" -msgid "No results found" +msgid "Search {{uniqueAttrName}}" +msgstr "" + +msgid "Search by attributes" +msgstr "" + +msgid "Could not retrieve metadata. Please try again later." +msgstr "" + +msgid "Possible duplicates found" msgstr "" msgid "An error occurred loading possible duplicates" @@ -1011,9 +1035,6 @@ msgstr "" msgid "Search by {{name}}" msgstr "" -msgid "Search by attributes" -msgstr "" - msgid "all programs" msgstr "" @@ -1065,12 +1086,6 @@ msgstr "" msgid "Results found" msgstr "" -msgid "Selected program" -msgstr "" - -msgid "Search {{uniqueAttrName}}" -msgstr "" - msgid "Saved lists in this program" msgstr "" @@ -1160,6 +1175,33 @@ msgstr "" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Latitud" + +msgid "Longitude" +msgstr "Longitud" + +msgid "Edit" +msgstr "" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "" + +msgid "Delete polygon" +msgstr "" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "" + msgid "Enrollment date" msgstr "Fecha de inscripción" @@ -1184,6 +1226,12 @@ msgstr "" msgid "Cancelled" msgstr "Cancelar" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1306,9 +1354,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "Perfil de {{TETName}} " -msgid "Edit" -msgstr "" - msgid "tracked entity instance" msgstr "" @@ -1345,13 +1390,47 @@ msgstr "" msgid "Stages and Events" msgstr "" -msgid "Working list could not be loaded" +msgid "New TEI Relationship" msgstr "" -msgid "Download as JSON" +msgid "Missing implementation step" +msgstr "" + +msgid "Go back without saving relationship" +msgstr "" + +msgid "New Relationship" msgstr "" -msgid "Download as XML" +msgid "Link to an existing {{tetName}}" +msgstr "" + +msgid "An error occurred while adding the relationship" +msgstr "" + +msgid "" +"Something went wrong while loading relationships. Please try again later." +msgstr "" + +msgid "{{trackedEntityTypeName}} relationships" +msgstr "" + +msgid "To open this relationship, please wait until saving is complete" +msgstr "" + +msgid "Type" +msgstr "" + +msgid "Created date" +msgstr "" + +msgid "Program stage name" +msgstr "" + +msgid "Working list could not be loaded" +msgstr "" + +msgid "Download as JSON" msgstr "" msgid "Download as CSV" @@ -1522,12 +1601,6 @@ msgstr "" msgid "Page {{currentPage}}" msgstr "" -msgid "Delete polygon" -msgstr "" - -msgid "Set area" -msgstr "" - msgid "Area on map saved" msgstr "" diff --git a/i18n/fr.po b/i18n/fr.po index 9e40ff42d3..4c1f686a40 100644 --- a/i18n/fr.po +++ b/i18n/fr.po @@ -1,21 +1,21 @@ # # Translators: # Edem Kossi , 2022 -# Philip Larsen Donnelly, 2022 # Karoline Tufte Lien , 2022 # tx_e2f_fr r25 , 2022 # Bram Piot , 2022 # Yao Selom SAKA (HISP WCA) , 2023 # Yayra Gomado , 2023 -# Viktor Varland , 2023 # Gabriela Rodriguez , 2023 +# Viktor Varland , 2023 +# Philip Larsen Donnelly, 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Gabriela Rodriguez , 2023\n" +"Last-Translator: Philip Larsen Donnelly, 2023\n" "Language-Team: French (https://app.transifex.com/hisp-uio/teams/100509/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -557,6 +557,9 @@ msgstr "commencer à saisir pour effectuer une recherche" msgid "suggestions could not be retrieved" msgstr "les suggestions n'ont pas pu être récupérées" +msgid "No results found" +msgstr "Aucun résultat trouvé" + msgid "No items to display" msgstr "Aucun élément à afficher" @@ -995,9 +998,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "Doublons éventuellement détectés" -msgid "No results found" -msgstr "Aucun résultat trouvé" - msgid "An error occurred loading possible duplicates" msgstr "Une erreur s'est produite lors du chargement des doublons possibles" @@ -1213,6 +1213,33 @@ msgstr "Marquer pour suivi" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Latitude" + +msgid "Longitude" +msgstr "Longitude" + +msgid "Edit" +msgstr "Modifier" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Coordonnées" + +msgid "Delete polygon" +msgstr "Supprimer polygone" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "Définir l'aire" + msgid "Enrollment date" msgstr "Date d'enrôlement" @@ -1238,6 +1265,12 @@ msgstr "Dernière mise à jour {{date}}" msgid "Cancelled" msgstr "Annulé" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "Commentaires sur cette inscription" @@ -1374,9 +1407,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "Profil {{Nom de la TET}}" -msgid "Edit" -msgstr "Modifier" - msgid "tracked entity instance" msgstr "instance d'entité suivie" @@ -1629,12 +1659,6 @@ msgstr "À" msgid "Page {{currentPage}}" msgstr "Page {{page en cours}}" -msgid "Delete polygon" -msgstr "Supprimer polygone" - -msgid "Set area" -msgstr "Définir l'aire" - msgid "Area on map saved" msgstr "" diff --git a/i18n/id.po b/i18n/id.po index b22da534fd..065b73ed4c 100644 --- a/i18n/id.po +++ b/i18n/id.po @@ -3,19 +3,19 @@ # Carwoto Sa'an , 2021 # Yusuf Setiawan , 2021 # Guardian Sanjaya , 2022 -# Untoro Dwi Raharjo , 2023 # Philip Larsen Donnelly, 2023 # Raja Fathurrahim, 2023 # Farida Sibuea , 2023 -# Viktor Varland , 2023 # Aprisa Chrysantina , 2023 +# Viktor Varland , 2023 +# Untoro Dwi Raharjo , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Aprisa Chrysantina , 2023\n" +"Last-Translator: Untoro Dwi Raharjo , 2023\n" "Language-Team: Indonesian (https://app.transifex.com/hisp-uio/teams/100509/id/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -544,6 +544,9 @@ msgstr "mulai mengetik untuk mencari" msgid "suggestions could not be retrieved" msgstr "saran tidak dapat diambil" +msgid "No results found" +msgstr "Tidak ada hasil ditemukan" + msgid "No items to display" msgstr "Tidak ada item untuk ditampilkan" @@ -972,9 +975,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "Kemungkinan duplikat ditemukan" -msgid "No results found" -msgstr "Tidak ada hasil ditemukan" - msgid "An error occurred loading possible duplicates" msgstr "Terjadi kesalahan saat memuat kemungkinan duplikat" @@ -1181,6 +1181,33 @@ msgstr "Tandai untuk follow up" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Garis lintang" + +msgid "Longitude" +msgstr "Garis bujur" + +msgid "Edit" +msgstr "Sunting" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Koordinat" + +msgid "Delete polygon" +msgstr "Hapus poligon" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "Setel luas" + msgid "Enrollment date" msgstr "Tanggal pendaftaran" @@ -1205,6 +1232,12 @@ msgstr "Terakhir diperbarui {{date}}" msgid "Cancelled" msgstr "Dibatalkan" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "Komentar tentang pendaftaran ini" @@ -1327,9 +1360,6 @@ msgstr "Widget profil tidak dapat dimuat. Silakan coba lagi nanti" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "Sunting" - msgid "tracked entity instance" msgstr "contoh entitas yang dilacak" @@ -1577,12 +1607,6 @@ msgstr "Ke waktu" msgid "Page {{currentPage}}" msgstr "Halaman {{Halaman saat ini}}" -msgid "Delete polygon" -msgstr "Hapus poligon" - -msgid "Set area" -msgstr "Setel luas" - msgid "Area on map saved" msgstr "" diff --git a/i18n/km.po b/i18n/km.po index a36bcf4e1a..cdd9ea090a 100644 --- a/i18n/km.po +++ b/i18n/km.po @@ -1,15 +1,15 @@ # # Translators: # Philip Larsen Donnelly, 2022 -# Viktor Varland , 2022 # channara rin, 2023 +# Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-09-04T07:07:59.195Z\n" +"POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: channara rin, 2023\n" +"Last-Translator: Viktor Varland , 2023\n" "Language-Team: Khmer (https://app.transifex.com/hisp-uio/teams/100509/km/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -153,6 +153,15 @@ msgstr "" msgid "Enrollment" msgstr "" +msgid "Complete event" +msgstr "" + +msgid "{{ stageName }} - Basic info" +msgstr "" + +msgid "{{ stageName }} - Status" +msgstr "" + msgid "Please select {{categoryName}}" msgstr "" @@ -171,13 +180,16 @@ msgstr "បោះបង់" msgid "Metadata error. see log for details" msgstr "" -msgid "Assigned user" +msgid "{{ stageName }} - Details" msgstr "" -msgid "Search for user" +msgid "{{ stageName }} - {{ sectionName }}" msgstr "" -msgid "Complete event" +msgid "Assigned user" +msgstr "" + +msgid "Search for user" msgstr "" msgid "Basic info" @@ -510,6 +522,9 @@ msgstr "" msgid "suggestions could not be retrieved" msgstr "" +msgid "No results found" +msgstr "មិនមានលទ្ធផលបង្ហាញ" + msgid "No items to display" msgstr "" @@ -913,11 +928,20 @@ msgstr "" msgid "Organisation unit could not be loaded" msgstr "" -msgid "Possible duplicates found" +msgid "Selected program" msgstr "" -msgid "No results found" -msgstr "មិនមានលទ្ធផលបង្ហាញ" +msgid "Search {{uniqueAttrName}}" +msgstr "" + +msgid "Search by attributes" +msgstr "" + +msgid "Could not retrieve metadata. Please try again later." +msgstr "" + +msgid "Possible duplicates found" +msgstr "" msgid "An error occurred loading possible duplicates" msgstr "" @@ -977,9 +1001,6 @@ msgstr "" msgid "Search by {{name}}" msgstr "" -msgid "Search by attributes" -msgstr "" - msgid "all programs" msgstr "" @@ -1031,12 +1052,6 @@ msgstr "" msgid "Results found" msgstr "" -msgid "Selected program" -msgstr "" - -msgid "Search {{uniqueAttrName}}" -msgstr "" - msgid "Saved lists in this program" msgstr "" @@ -1126,6 +1141,33 @@ msgstr "" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "រយៈទទឹង" + +msgid "Longitude" +msgstr "រយៈបណ្តោយ" + +msgid "Edit" +msgstr "កែសម្រួល​" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "" + +msgid "Delete polygon" +msgstr "" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "" + msgid "Enrollment date" msgstr "ថ្ងៃខែឆ្នាំចុះឈ្មោះ" @@ -1150,6 +1192,12 @@ msgstr "" msgid "Cancelled" msgstr "បានលុបចោល" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1272,9 +1320,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "កែសម្រួល​" - msgid "tracked entity instance" msgstr "" @@ -1311,13 +1356,47 @@ msgstr "" msgid "Stages and Events" msgstr "" -msgid "Working list could not be loaded" +msgid "New TEI Relationship" msgstr "" -msgid "Download as JSON" +msgid "Missing implementation step" +msgstr "" + +msgid "Go back without saving relationship" +msgstr "" + +msgid "New Relationship" msgstr "" -msgid "Download as XML" +msgid "Link to an existing {{tetName}}" +msgstr "" + +msgid "An error occurred while adding the relationship" +msgstr "" + +msgid "" +"Something went wrong while loading relationships. Please try again later." +msgstr "" + +msgid "{{trackedEntityTypeName}} relationships" +msgstr "" + +msgid "To open this relationship, please wait until saving is complete" +msgstr "" + +msgid "Type" +msgstr "" + +msgid "Created date" +msgstr "" + +msgid "Program stage name" +msgstr "" + +msgid "Working list could not be loaded" +msgstr "" + +msgid "Download as JSON" msgstr "" msgid "Download as CSV" @@ -1488,12 +1567,6 @@ msgstr "" msgid "Page {{currentPage}}" msgstr "" -msgid "Delete polygon" -msgstr "" - -msgid "Set area" -msgstr "" - msgid "Area on map saved" msgstr "" diff --git a/i18n/lo.po b/i18n/lo.po index 0521d1c02a..21bbeecd37 100644 --- a/i18n/lo.po +++ b/i18n/lo.po @@ -1,16 +1,16 @@ # # Translators: -# Thuy Nguyen , 2022 # Saysamone Sibounma, 2023 -# Viktor Varland , 2023 # Philip Larsen Donnelly, 2023 +# Viktor Varland , 2023 +# Thuy Nguyen , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Philip Larsen Donnelly, 2023\n" +"Last-Translator: Thuy Nguyen , 2023\n" "Language-Team: Lao (https://app.transifex.com/hisp-uio/teams/100509/lo/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -523,6 +523,9 @@ msgstr "" msgid "suggestions could not be retrieved" msgstr "" +msgid "No results found" +msgstr "" + msgid "No items to display" msgstr "" @@ -941,9 +944,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "" -msgid "No results found" -msgstr "" - msgid "An error occurred loading possible duplicates" msgstr "" @@ -1142,6 +1142,33 @@ msgstr "ໝາຍໄວ້ເພື່ອຕິດຕາມ" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "ເສັ້ນຂະໜານ" + +msgid "Longitude" +msgstr "ເສັ້ນແວງ" + +msgid "Edit" +msgstr "ແກ້ໄຂ" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Coordinates" + +msgid "Delete polygon" +msgstr "" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "" + msgid "Enrollment date" msgstr "ວັນທີ່ລົງທະບຽນ" @@ -1166,6 +1193,12 @@ msgstr "" msgid "Cancelled" msgstr "ຍົກເລີກແລ້ວ" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1288,9 +1321,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "ແກ້ໄຂ" - msgid "tracked entity instance" msgstr "" @@ -1538,12 +1568,6 @@ msgstr "" msgid "Page {{currentPage}}" msgstr "" -msgid "Delete polygon" -msgstr "" - -msgid "Set area" -msgstr "" - msgid "Area on map saved" msgstr "" diff --git a/i18n/nb.po b/i18n/nb.po index e562d46e97..00e615f61b 100644 --- a/i18n/nb.po +++ b/i18n/nb.po @@ -1,14 +1,14 @@ # # Translators: -# Karoline Tufte Lien , 2023 # Caroline Hesthagen Holen , 2023 +# Karoline Tufte Lien , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Caroline Hesthagen Holen , 2023\n" +"Last-Translator: Karoline Tufte Lien , 2023\n" "Language-Team: Norwegian Bokmål (https://app.transifex.com/hisp-uio/teams/100509/nb/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -540,6 +540,9 @@ msgstr "begynn å skrive for å søke" msgid "suggestions could not be retrieved" msgstr "forslag kunne ikke hentes" +msgid "No results found" +msgstr "Ingen resultater funnet" + msgid "No items to display" msgstr "Ingen elementer å vise" @@ -983,9 +986,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "Mulige duplikater funnet" -msgid "No results found" -msgstr "Ingen resultater funnet" - msgid "An error occurred loading possible duplicates" msgstr "En feil oppsto ved lasting av mulige duplikater" @@ -1199,6 +1199,33 @@ msgstr "" "Eksisterende datoer for automatisk genererte hendelser vil ikke bli " "oppdatert." +msgid "Latitude" +msgstr "Breddegrad" + +msgid "Longitude" +msgstr "Lengdegrad" + +msgid "Edit" +msgstr "Rediger" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Koordinater" + +msgid "Delete polygon" +msgstr "Slett polygon" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "Sett område" + msgid "Enrollment date" msgstr "Registreringsdato" @@ -1223,6 +1250,12 @@ msgstr "Sist oppdatert {{date}}" msgid "Cancelled" msgstr "Kansellert" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "Kommentarer om denne registreringen" @@ -1351,9 +1384,6 @@ msgstr "Profil -widgeten kunne ikke lastes inn. Prøv igjen senere" msgid "{{TETName}} profile" msgstr "{{TETName}} profil" -msgid "Edit" -msgstr "Rediger" - msgid "tracked entity instance" msgstr "Sporet enhetforekomst" @@ -1601,12 +1631,6 @@ msgstr "Til klokkeslett" msgid "Page {{currentPage}}" msgstr "Side {{currentPage}}" -msgid "Delete polygon" -msgstr "Slett polygon" - -msgid "Set area" -msgstr "Sett område" - msgid "Area on map saved" msgstr "Området på kartet er lagret" diff --git a/i18n/nl.po b/i18n/nl.po index 4a2d38b67b..bc73cff5d8 100644 --- a/i18n/nl.po +++ b/i18n/nl.po @@ -546,6 +546,9 @@ msgstr "begin met typen om te zoeken" msgid "suggestions could not be retrieved" msgstr "suggesties konden niet worden opgehaald" +msgid "No results found" +msgstr "Geen resultaten gevonden" + msgid "No items to display" msgstr "Geen items om weer te geven" @@ -1000,9 +1003,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "Mogelijke duplicaten gevonden" -msgid "No results found" -msgstr "Geen resultaten gevonden" - msgid "An error occurred loading possible duplicates" msgstr "Er is een fout opgetreden bij het laden van mogelijke duplicaten" @@ -1220,6 +1220,33 @@ msgstr "Markeer voor vervolg" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Breedtegraad" + +msgid "Longitude" +msgstr "Lengtegraad" + +msgid "Edit" +msgstr "Bewerk" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "" + +msgid "Delete polygon" +msgstr "Polygoon verwijderen" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "Gebied instellen" + msgid "Enrollment date" msgstr "Inschrijvingsdatum" @@ -1245,6 +1272,12 @@ msgstr "Laatst bijgewerkt {{datum}}" msgid "Cancelled" msgstr "Geannuleerd" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "Opmerkingen over deze inschrijving" @@ -1378,9 +1411,6 @@ msgstr "Profielwidget kan niet worden geladen. Probeer het later opnieuw" msgid "{{TETName}} profile" msgstr "{{TETNaam}} profiel" -msgid "Edit" -msgstr "Bewerk" - msgid "tracked entity instance" msgstr "gevolgd entiteitsexemplaar" @@ -1633,12 +1663,6 @@ msgstr "Timen" msgid "Page {{currentPage}}" msgstr "Pagina {{huidigePagina}}" -msgid "Delete polygon" -msgstr "Polygoon verwijderen" - -msgid "Set area" -msgstr "Gebied instellen" - msgid "Area on map saved" msgstr "Gebied op kaart opgeslagen" diff --git a/i18n/or.po b/i18n/or.po index 3e1d979be6..572b2755bf 100644 --- a/i18n/or.po +++ b/i18n/or.po @@ -1,14 +1,14 @@ # # Translators: -# SubhamJena , 2022 +# SubhamJena , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2022-08-17T08:14:13.865Z\n" +"POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: SubhamJena , 2022\n" -"Language-Team: Odia (https://www.transifex.com/hisp-uio/teams/100509/or/)\n" +"Last-Translator: SubhamJena , 2023\n" +"Language-Team: Odia (https://app.transifex.com/hisp-uio/teams/100509/or/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -36,6 +36,27 @@ msgid "" "again, but be aware that this will close other versions." msgstr "" +msgid "View {{programName}} dashboard" +msgstr "" + +msgid "View dashboard" +msgstr "" + +msgid "View active enrollment" +msgstr "" + +msgid "Re-enroll" +msgstr "" + +msgid "in" +msgstr "" + +msgid "Enrolled" +msgstr "" + +msgid "Previously enrolled" +msgstr "" + msgid "Organisation unit" msgstr "" @@ -45,10 +66,14 @@ msgstr "" msgid "Last updated" msgstr "" -msgid "Enrolled" +msgid "error encountered during field validation" msgstr "" -msgid "Previously enrolled" +msgid "error" +msgstr "" + +msgid "" +"Plugins are not yet available - Please contact your system administrator" msgstr "" msgid "This value is validating" @@ -87,7 +112,7 @@ msgstr "" msgid "Please provide a valid time" msgstr "" -msgid "Please provide a valid percentage" +msgid "Please provide an integer between 0 and 100" msgstr "" msgid "Please provide a valid url" @@ -126,6 +151,18 @@ msgstr "" msgid "Enrollment" msgstr "" +msgid "Complete event" +msgstr "" + +msgid "{{ stageName }} - Basic info" +msgstr "" + +msgid "{{ stageName }} - Status" +msgstr "" + +msgid "Please select {{categoryName}}" +msgstr "" + msgid "A future date is not allowed" msgstr "" @@ -141,13 +178,16 @@ msgstr "" msgid "Metadata error. see log for details" msgstr "" -msgid "Assigned user" +msgid "{{ stageName }} - Details" msgstr "" -msgid "Search for user" +msgid "{{ stageName }} - {{ sectionName }}" msgstr "" -msgid "Complete event" +msgid "Assigned user" +msgstr "" + +msgid "Search for user" msgstr "" msgid "Basic info" @@ -232,7 +272,7 @@ msgstr "" msgid "Go back to event without saving relationship" msgstr "" -msgid "Unsaved changes" +msgid "Discard unsaved changes?" msgstr "" msgid "" @@ -240,10 +280,10 @@ msgid "" "relationship" msgstr "" -msgid "Yes, discard" +msgid "Yes, discard changes" msgstr "" -msgid "No, stay here" +msgid "No, cancel" msgstr "" msgid "New event" @@ -264,9 +304,6 @@ msgstr "" msgid "enrollment" msgstr "" -msgid "in" -msgstr "" - msgid "Enroll in a program by selecting a program from the top bar." msgstr "" @@ -295,9 +332,6 @@ msgstr "" msgid "Registered person" msgstr "" -msgid "Leaving this page will discard the changes you made to this event." -msgstr "" - msgid "validation failed" msgstr "" @@ -313,10 +347,13 @@ msgstr "" msgid "Warnings" msgstr "" -msgid "Warnings found" +msgid "Generate new event" msgstr "" -msgid "Abort" +msgid "Do you want to create another event?" +msgstr "" + +msgid "Yes, create new event" msgstr "" msgid "Back to form" @@ -340,7 +377,9 @@ msgstr "" msgid "Operations running" msgstr "" -msgid "Sort" +msgid "" +"This event has unsaved changes. Leaving this page without saving will lose " +"these changes. Are you sure you want to discard unsaved changes?" msgstr "" msgid "No events to display" @@ -451,6 +490,12 @@ msgstr "" msgid "Select image" msgstr "" +msgid "Type to filter options" +msgstr "" + +msgid "No match found" +msgstr "" + msgid "Search" msgstr "" @@ -475,6 +520,9 @@ msgstr "" msgid "suggestions could not be retrieved" msgstr "" +msgid "No results found" +msgstr "" + msgid "No items to display" msgstr "" @@ -493,6 +541,9 @@ msgstr "" msgid "Reset filter" msgstr "" +msgid "Remove filter" +msgstr "" + msgid "{{fromDate}} to {{toDate}}" msgstr "" @@ -511,6 +562,9 @@ msgstr "" msgid "More filters" msgstr "" +msgid "Stage filters" +msgstr "" + msgid "Rows per page" msgstr "" @@ -535,19 +589,46 @@ msgstr "" msgid "Add comment" msgstr "" -msgid "You dont have access to write comments" +msgid "You don't have access to write comments" msgstr "" msgid "Write comment" msgstr "" +msgid "was blanked out and hidden by your last action" +msgstr "" + +msgid "Notice" +msgstr "" + +msgid "Close the notice" +msgstr "" + msgid "Use new Enrollment dashboard for {{programName}}" msgstr "" msgid "Opt in for {{programName}}" msgstr "" -msgid "No, cancel" +msgid "" +"By clicking opt-in below, you will start using the new enrollment dashboard " +"in the Capture app for this Tracker program. At the moment, there is certain" +" functionality from Tracker Capture that has not yet been added, including " +"relationship and referral functionality. The work on including this Tracker " +"functionality in Capture is ongoing and will be added in upcoming app " +"releases." +msgstr "" + +msgid "" +"The core team appreciates any feedback on this new functionality which is " +"currently being beta tested, please report any issues and feedback in the " +"DHIS2 JIRA project." +msgstr "" + +msgid "" +"Click the button below to opt-in to the new enrollment dashboard " +"functionality in the Capture app (beta) for this Tracker program for all " +"users." msgstr "" msgid "Yes, opt in" @@ -566,7 +647,8 @@ msgid "" "There is an error while opening this enrollment. Please enter a valid url." msgstr "" -msgid "Enrollment with id \"{{enrollmentId}}\" does not exist" +msgid "" +"An error occurred while fetching enrollments. Please enter a valid url." msgstr "" msgid "Enrollment Dashboard" @@ -605,9 +687,21 @@ msgid "" "{{programName}} has categories. Choose all categories to view dashboard." msgstr "" +msgid "Invalid enrollment id {{enrollmentId}}." +msgstr "" + msgid "Choose an enrollment to view the dashboard." msgstr "" +msgid "There are no active enrollments." +msgstr "" + +msgid "Add new enrollment for {{teiDisplayName}} in this program." +msgstr "" + +msgid "No access to program owner." +msgstr "" + msgid "{{teiDisplayName}} is not enrolled in this program." msgstr "" @@ -670,7 +764,7 @@ msgstr "" msgid "Refer" msgstr "" -msgid "You can’t add any more events in this program" +msgid "You can't add any more {{ programStageName }} events" msgstr "" msgid "Cancel without saving" @@ -682,7 +776,7 @@ msgstr "" msgid "Program Stages could not be loaded" msgstr "" -msgid "stage" +msgid "Stage" msgstr "" msgid "Enrollment{{escape}} View Event" @@ -721,9 +815,6 @@ msgstr "" msgid "Save as new" msgstr "" -msgid "View dashboard" -msgstr "" - msgid "View enrollment" msgstr "" @@ -737,7 +828,10 @@ msgstr "" msgid "New Enrollment in program{{escape}} {{programName}}" msgstr "" -msgid "Save new" +msgid "Save {{trackedEntityTypeName}}" +msgstr "" + +msgid "Save {{trackedEntityName}}" msgstr "" msgid "Save new {{trackedEntityTypeName}} and link" @@ -785,213 +879,220 @@ msgstr "" msgid "Register" msgstr "" -msgid "" -"Fill in at least {{minAttributesRequiredToSearch}} attributes to search" +msgid "Back" msgstr "" -msgid "Search {{name}}" +msgid "events" msgstr "" -msgid "Search by {{name}}" +msgid "event" msgstr "" -msgid "Search by attributes" +msgid "You don't have access to edit this event" msgstr "" -msgid "Fill in these fields to search{{escape}} {{ searchableAttributes }}" +msgid "Edit event" +msgstr "" + +msgid "Event details" msgstr "" msgid "" -"Fill in at least {{minAttributesRequiredToSearch}} of these fields to " -"search{{escape}} {{searchableAttributes}}" +"Leaving this page will discard any selections you made for a new " +"relationship" msgstr "" -msgid "Fill in this field to search{{escape}} {{searchableAttributes}}" +msgid "No one is assigned to this event" msgstr "" -msgid "Back" +msgid "Assign" msgstr "" -msgid "Search for {{titleText}}" +msgid "Event assigned to {{name}}" msgstr "" -msgid "Search for" +msgid "Feedbacks" msgstr "" -msgid "" -"You can also choose a program from the top bar and search in that program" +msgid "Show all events" msgstr "" -msgid "No results found" +msgid "Event could not be loaded. Are you sure it exists?" msgstr "" -msgid "" -"You can change your search terms and search again to find what you are " -"looking for." +msgid "Event could not be loaded" msgstr "" -msgid "Register a user" +msgid "Organisation unit could not be loaded" msgstr "" -msgid "Back to search" +msgid "Selected program" msgstr "" -msgid "An error has occurred" +msgid "Search {{uniqueAttrName}}" msgstr "" -msgid "" -"There is a problem with this search, please change the search terms or try " -"again later. For more details open the Console tab of the Developer tools" +msgid "Search by attributes" msgstr "" -msgid "Too many results" +msgid "Could not retrieve metadata. Please try again later." msgstr "" -msgid "" -"This search returned too many results to show. Try changing search terms or " -"searching by more attributes to narrow down the results." +msgid "Possible duplicates found" msgstr "" -msgid "Cannot search in all programs" +msgid "An error occurred loading possible duplicates" msgstr "" -msgid "Choose a type to start searching" +msgid "You don't have access to delete this relationship" msgstr "" -msgid "View active enrollment" +msgid "You don't have access to create any relationships" msgstr "" -msgid "Re-enroll" +msgid "Add relationship" msgstr "" -msgid "all programs" +msgid "No results found for " msgstr "" -msgid "If none of search results match, you can create new " +msgid "Registering unit" msgstr "" -msgid "Create new" +msgid "Choose a registering unit" msgstr "" -msgid "" -"Not finding the results you were looking for? Try to search all programs " -"that use type " +msgid "Clear selection" msgstr "" -msgid "Search in all programs" +msgid "No programs available." msgstr "" -msgid "events" +msgid "Search for a program" msgstr "" -msgid "event" +msgid "Some programs are being filtered by the chosen registering unit" msgstr "" -msgid "You dont have access to edit this event" +msgid "Show all programs" msgstr "" -msgid "Edit event" +msgid "Choose a program" msgstr "" -msgid "Event details" +msgid "Search for {{titleText}}" +msgstr "" + +msgid "Search for" msgstr "" msgid "" -"Leaving this page will discard any selections you made for a new " -"relationship" +"You can also choose a program from the top bar and search in that program" msgstr "" -msgid "No one is assigned to this event" +msgid "Choose a type to start searching" msgstr "" -msgid "Assign" +msgid "Search {{name}}" msgstr "" -msgid "Event assigned to {{name}}" +msgid "Search by {{name}}" msgstr "" -msgid "Feedbacks" +msgid "all programs" msgstr "" -msgid "Show all events" +msgid "" +"Not finding the results you were looking for? Try to search all programs " +"that use type " msgstr "" -msgid "Event could not be loaded. Are you sure it exists?" +msgid "Search in all programs" msgstr "" -msgid "Event could not be loaded" +msgid "If none of search results match, you can create a new " msgstr "" -msgid "Organisation unit could not be loaded" +msgid "Create new" msgstr "" -msgid "Possible duplicates found" +msgid "Fill in these fields to search{{escape}} {{ searchableAttributes }}" msgstr "" -msgid "An error occurred loading possible duplicates" +msgid "" +"Fill in at least {{minAttributesRequiredToSearch}} of these fields to " +"search{{escape}} {{searchableAttributes}}" msgstr "" -msgid "You dont have access to delete this relationship" +msgid "Fill in this field to search{{escape}} {{searchableAttributes}}" msgstr "" -msgid "You dont have access to create any relationships" +msgid "" +"You can change your search terms and search again to find what you are " +"looking for." msgstr "" -msgid "Add relationship" +msgid "Back to search" msgstr "" -msgid "Selected registering unit" +msgid "An error has occurred" msgstr "" -msgid "Start Again" +msgid "Too many results" msgstr "" -msgid "Are you sure? All unsaved data will be lost." +msgid "Cannot search in all programs" msgstr "" -msgid "Accept" +msgid "Missing search criteria" msgstr "" -msgid "Registering Organisation Unit" +msgid "Results found" msgstr "" -msgid "Select" +msgid "Saved lists in this program" msgstr "" -msgid "No programs available." +msgid "Saved lists offer quick access to your most used views in a program." msgstr "" -msgid "Selected program" +msgid "" +"There are no saved lists in this program yet, create one using the button " +"below." msgstr "" -msgid "Select program" +msgid "Create saved list" msgstr "" -msgid "Selected" +msgid "New {{trackedEntityName}} in {{programName}}" msgstr "" -msgid "Results found" +msgid "Search for a {{trackedEntityName}} in {{programName}}" msgstr "" -msgid "Search {{uniqueAttrName}}" +msgid "To work with the selected program," msgstr "" -msgid "Fill in at least {{minAttributesRequired}} attributes to search" +msgid "open the Tracker Capture app" msgstr "" -msgid "New {{trackedEntityName}} in {{programName}}" +msgid "This program is protected" msgstr "" -msgid "Search for a {{trackedEntityName}} in {{programName}}" +msgid "Reason to check for enrollments" msgstr "" -msgid "Clear selections" +msgid "" +"Describe the reason you are checking for enrollments in this protected " +"program" msgstr "" -msgid "To work with the selected program," +msgid "Check for enrollments" msgstr "" -msgid "open the Tracker Capture app" +msgid "" +"You must provide a reason to check for enrollments in this protected " +"program. All activity will be logged." msgstr "" msgid "Save comment" @@ -1003,10 +1104,10 @@ msgstr "" msgid "We are processing your request." msgstr "" -msgid "Add new" +msgid "Only one enrollment per {{tetName}} is allowed in this program" msgstr "" -msgid "Only one enrollment per {{tetName}} is allowed in this program" +msgid "Add new" msgstr "" msgid "Reactivate" @@ -1035,6 +1136,36 @@ msgstr "" msgid "Mark for follow-up" msgstr "" +msgid "Existing dates for auto-generated events will not be updated." +msgstr "" + +msgid "Latitude" +msgstr "ଅକ୍ଷାଂଶ" + +msgid "Longitude" +msgstr "ଦ୍ରାଘିମା" + +msgid "Edit" +msgstr "" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "" + +msgid "Delete polygon" +msgstr "" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "" + msgid "Enrollment date" msgstr "" @@ -1059,6 +1190,12 @@ msgstr "" msgid "Cancelled" msgstr "" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1101,40 +1238,34 @@ msgstr "" msgid "Yes, delete event" msgstr "" +msgid "Go to “Schedule” tab to reschedule this event" +msgstr "" + +msgid "Scheduled date cannot be changed for {{ eventStatus }} events" +msgstr "" + msgid "Event completed" msgstr "" msgid "Back to all stages and events" msgstr "" -msgid "You don't have access to edit this event" +msgid "Schedule date info" msgstr "" -msgid "Schedule date info" +msgid "Scheduled automatically for {{suggestedScheduleDate}}" msgstr "" msgid "" -"This date is the suggested scheduled date based on the intervals defined, \n" -" it can be adjusted if needed." +"The scheduled date matches the suggested date, but can be changed if needed." msgstr "" -msgid "This date is {{count}} days {{position}} the suggested date." -msgid_plural "This date is {{count}} days {{position}} the suggested date." -msgstr[0] "" -msgstr[1] "" - msgid "after" msgstr "" msgid "before" msgstr "" -msgid "There are {{count}} scheduled event in {{orgUnitName}} on this day." -msgid_plural "" -"There are {{count}} scheduled event in {{orgUnitName}} on this day." -msgstr[0] "" -msgstr[1] "" - msgid "" "Scheduling an event in {{stageName}} for {{programName}} in {{orgUnitName}}" msgstr "" @@ -1178,9 +1309,6 @@ msgstr "" msgid "Try again or contact your system administrator for support" msgstr "" -msgid "tracked entity instance" -msgstr "" - msgid "Fix errors in the form to continue." msgstr "" @@ -1190,13 +1318,13 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" +msgid "tracked entity instance" msgstr "" msgid "New {{ eventName }} event" msgstr "" -msgid "This event is not yet preserved and cannot be edited" +msgid "To open this event, please wait until saving is complete" msgstr "" msgid "Show {{ rest }} more" @@ -1214,9 +1342,6 @@ msgstr "" msgid "Events could not be retrieved. Please try again later." msgstr "" -msgid "Registering unit" -msgstr "" - msgid "{{ totalEvents }} events" msgstr "" @@ -1229,13 +1354,47 @@ msgstr "" msgid "Stages and Events" msgstr "" -msgid "Working list could not be loaded" +msgid "New TEI Relationship" msgstr "" -msgid "Download as JSON" +msgid "Missing implementation step" +msgstr "" + +msgid "Go back without saving relationship" +msgstr "" + +msgid "New Relationship" +msgstr "" + +msgid "Link to an existing {{tetName}}" +msgstr "" + +msgid "An error occurred while adding the relationship" +msgstr "" + +msgid "" +"Something went wrong while loading relationships. Please try again later." +msgstr "" + +msgid "{{trackedEntityTypeName}} relationships" +msgstr "" + +msgid "To open this relationship, please wait until saving is complete" +msgstr "" + +msgid "Type" msgstr "" -msgid "Download as XML" +msgid "Created date" +msgstr "" + +msgid "Program stage name" +msgstr "" + +msgid "Working list could not be loaded" +msgstr "" + +msgid "Download as JSON" msgstr "" msgid "Download as CSV" @@ -1250,9 +1409,6 @@ msgstr "" msgid "an error occurred loading working lists" msgstr "" -msgid "Enrollment status" -msgstr "" - msgid "Assigned to" msgstr "" @@ -1262,9 +1418,27 @@ msgstr "" msgid "Inactive" msgstr "" +msgid "Enrollment status" +msgstr "" + +msgid "Choose a program stage to filter by {{label}}" +msgstr "" + +msgid "Active enrollments" +msgstr "" + +msgid "Completed enrollments" +msgstr "" + +msgid "Cancelled enrollments" +msgstr "" + msgid "Working list could not be updated" msgstr "" +msgid "an error occurred loading the working lists" +msgstr "" + msgid "an error occurred loading Tracked entity instance lists" msgstr "" @@ -1319,6 +1493,9 @@ msgstr "" msgid "Skipped" msgstr "" +msgid "Visited" +msgstr "" + msgid "{{trackedEntityName}} in program{{escape}} {{programName}}" msgstr "" @@ -1367,9 +1544,6 @@ msgstr "" msgid "Set coordinate" msgstr "" -msgid "Page {{currentPage}}" -msgstr "" - msgid "Date" msgstr "" @@ -1388,16 +1562,10 @@ msgstr "" msgid "To time" msgstr "" -msgid "error encountered during field validation" -msgstr "" - -msgid "error" -msgstr "" - -msgid "Delete polygon" +msgid "Page {{currentPage}}" msgstr "" -msgid "Set area" +msgid "Area on map saved" msgstr "" msgid "Compatibility mode" diff --git a/i18n/prs.po b/i18n/prs.po index 4ae583ebe5..f7a6858ec0 100644 --- a/i18n/prs.po +++ b/i18n/prs.po @@ -520,6 +520,9 @@ msgstr "" msgid "suggestions could not be retrieved" msgstr "" +msgid "No results found" +msgstr "هیج نتیجه ی یافت نشد" + msgid "No items to display" msgstr "" @@ -938,9 +941,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "" -msgid "No results found" -msgstr "هیج نتیجه ی یافت نشد" - msgid "An error occurred loading possible duplicates" msgstr "" @@ -1139,6 +1139,33 @@ msgstr "نشانی برای پیگیری" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "عرض البلد" + +msgid "Longitude" +msgstr "طول البلد" + +msgid "Edit" +msgstr "تجدید" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "ځانګړتیاوې" + +msgid "Delete polygon" +msgstr "" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "" + msgid "Enrollment date" msgstr "تاریخ شمولیت" @@ -1163,6 +1190,12 @@ msgstr "" msgid "Cancelled" msgstr "" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1285,9 +1318,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "تجدید" - msgid "tracked entity instance" msgstr "" @@ -1535,12 +1565,6 @@ msgstr "" msgid "Page {{currentPage}}" msgstr "" -msgid "Delete polygon" -msgstr "" - -msgid "Set area" -msgstr "" - msgid "Area on map saved" msgstr "" diff --git a/i18n/ps.po b/i18n/ps.po index 51a9bdd72a..6e904c62e5 100644 --- a/i18n/ps.po +++ b/i18n/ps.po @@ -1,14 +1,14 @@ # # Translators: -# Viktor Varland , 2023 # Philip Larsen Donnelly, 2023 +# Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Philip Larsen Donnelly, 2023\n" +"Last-Translator: Viktor Varland , 2023\n" "Language-Team: Pashto (https://app.transifex.com/hisp-uio/teams/100509/ps/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1140,6 +1140,33 @@ msgstr "د تعقيب لپاره يې په نښه کړئ" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "لېټېټيوډ" + +msgid "Longitude" +msgstr "لانګېټيوډ" + +msgid "Edit" +msgstr "درست یې کړئ" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "مختصات" + +msgid "Delete polygon" +msgstr "" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "" + msgid "Enrollment date" msgstr "د نوم ثبتونې نېټه" @@ -1164,6 +1191,12 @@ msgstr "" msgid "Cancelled" msgstr "لغوه شوی" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1286,9 +1319,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "درست یې کړئ" - msgid "tracked entity instance" msgstr "" @@ -1536,12 +1566,6 @@ msgstr "" msgid "Page {{currentPage}}" msgstr "" -msgid "Delete polygon" -msgstr "" - -msgid "Set area" -msgstr "" - msgid "Area on map saved" msgstr "" diff --git a/i18n/pt.po b/i18n/pt.po index cea52926b0..102c4482d0 100644 --- a/i18n/pt.po +++ b/i18n/pt.po @@ -547,6 +547,9 @@ msgstr "comece a digitar para pesquisar" msgid "suggestions could not be retrieved" msgstr "sugestões não puderam ser recuperadas" +msgid "No results found" +msgstr "Nenhum resultado encontrado" + msgid "No items to display" msgstr "Nenhum item para exibir" @@ -991,9 +994,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "Possíveis duplicatas encontradas" -msgid "No results found" -msgstr "Nenhum resultado encontrado" - msgid "An error occurred loading possible duplicates" msgstr "Ocorreu um erro ao carregar possíveis duplicatas" @@ -1211,6 +1211,33 @@ msgstr "Marcar para acompanhamento" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Latitude" + +msgid "Longitude" +msgstr "Longitude" + +msgid "Edit" +msgstr "Editar" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Coordenadas" + +msgid "Delete polygon" +msgstr "Excluir polígono" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "Definir área" + msgid "Enrollment date" msgstr "Data de inscrição" @@ -1237,6 +1264,12 @@ msgstr "Última atualização em {{date}}" msgid "Cancelled" msgstr "Cancelado" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "Comentários sobre esta inscrição" @@ -1371,9 +1404,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "{{TETName}} perfil" -msgid "Edit" -msgstr "Editar" - msgid "tracked entity instance" msgstr "instância de entidade rastreada" @@ -1625,12 +1655,6 @@ msgstr "Para o tempo" msgid "Page {{currentPage}}" msgstr "Página {{currentPage}}" -msgid "Delete polygon" -msgstr "Excluir polígono" - -msgid "Set area" -msgstr "Definir área" - msgid "Area on map saved" msgstr "Área no mapa gravada" diff --git a/i18n/pt_BR.po b/i18n/pt_BR.po index cca4b80e6f..fa227d2a98 100644 --- a/i18n/pt_BR.po +++ b/i18n/pt_BR.po @@ -1141,6 +1141,33 @@ msgstr "" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Latitude" + +msgid "Longitude" +msgstr "Longitude" + +msgid "Edit" +msgstr "Editar" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Coordenadas" + +msgid "Delete polygon" +msgstr "" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "" + msgid "Enrollment date" msgstr "" @@ -1165,6 +1192,12 @@ msgstr "" msgid "Cancelled" msgstr "" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1287,9 +1320,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "Editar" - msgid "tracked entity instance" msgstr "" @@ -1537,12 +1567,6 @@ msgstr "" msgid "Page {{currentPage}}" msgstr "" -msgid "Delete polygon" -msgstr "" - -msgid "Set area" -msgstr "" - msgid "Area on map saved" msgstr "" diff --git a/i18n/ru.po b/i18n/ru.po index 3ba772b823..95c94ed984 100644 --- a/i18n/ru.po +++ b/i18n/ru.po @@ -543,6 +543,9 @@ msgstr "Начинайте вводить для поиска" msgid "suggestions could not be retrieved" msgstr "Подсказка не может быть найдена" +msgid "No results found" +msgstr "Результаты не найдены" + msgid "No items to display" msgstr "Нет элементов для отображения" @@ -964,9 +967,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "Найдены возможные дубликаты" -msgid "No results found" -msgstr "Результаты не найдены" - msgid "An error occurred loading possible duplicates" msgstr "" @@ -1165,6 +1165,33 @@ msgstr "Отметить для последующего наблюдения" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Широта" + +msgid "Longitude" +msgstr "Долгота" + +msgid "Edit" +msgstr "Редактировать" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Координаты" + +msgid "Delete polygon" +msgstr "Удалить полигон" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "Установить площадь" + msgid "Enrollment date" msgstr "Дата зачисления" @@ -1189,6 +1216,12 @@ msgstr "" msgid "Cancelled" msgstr "Отмененный" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1311,9 +1344,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "Редактировать" - msgid "tracked entity instance" msgstr "Элемент отслеживаемого объекта" @@ -1561,12 +1591,6 @@ msgstr "ко времени" msgid "Page {{currentPage}}" msgstr "Страница {{currentPage}}" -msgid "Delete polygon" -msgstr "Удалить полигон" - -msgid "Set area" -msgstr "Установить площадь" - msgid "Area on map saved" msgstr "" diff --git a/i18n/sv.po b/i18n/sv.po index 12f88faefd..980919e391 100644 --- a/i18n/sv.po +++ b/i18n/sv.po @@ -1,15 +1,15 @@ # # Translators: -# Viktor Varland , 2023 # Jason Pickering , 2023 # Philip Larsen Donnelly, 2023 +# Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Philip Larsen Donnelly, 2023\n" +"Last-Translator: Viktor Varland , 2023\n" "Language-Team: Swedish (https://app.transifex.com/hisp-uio/teams/100509/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1141,6 +1141,33 @@ msgstr "" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Latitud" + +msgid "Longitude" +msgstr "Longitud" + +msgid "Edit" +msgstr "Redigera" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "koordinater" + +msgid "Delete polygon" +msgstr "" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "" + msgid "Enrollment date" msgstr "inskrivning datum" @@ -1165,6 +1192,12 @@ msgstr "" msgid "Cancelled" msgstr "Avbruten" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1287,9 +1320,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "Redigera" - msgid "tracked entity instance" msgstr "" @@ -1537,12 +1567,6 @@ msgstr "" msgid "Page {{currentPage}}" msgstr "" -msgid "Delete polygon" -msgstr "" - -msgid "Set area" -msgstr "" - msgid "Area on map saved" msgstr "" diff --git a/i18n/tg.po b/i18n/tg.po index e231a3fb60..76ef7fdb4d 100644 --- a/i18n/tg.po +++ b/i18n/tg.po @@ -1,14 +1,14 @@ # # Translators: -# Viktor Varland , 2023 # Philip Larsen Donnelly, 2023 +# Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Philip Larsen Donnelly, 2023\n" +"Last-Translator: Viktor Varland , 2023\n" "Language-Team: Tajik (https://app.transifex.com/hisp-uio/teams/100509/tg/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1140,6 +1140,33 @@ msgstr "" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Тӯл" + +msgid "Longitude" +msgstr "Арз" + +msgid "Edit" +msgstr "Таҳрир" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Координатаҳо" + +msgid "Delete polygon" +msgstr "" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "" + msgid "Enrollment date" msgstr "Санаи номнавис" @@ -1164,6 +1191,12 @@ msgstr "" msgid "Cancelled" msgstr "" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1286,9 +1319,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "Таҳрир" - msgid "tracked entity instance" msgstr "" @@ -1536,12 +1566,6 @@ msgstr "" msgid "Page {{currentPage}}" msgstr "" -msgid "Delete polygon" -msgstr "" - -msgid "Set area" -msgstr "" - msgid "Area on map saved" msgstr "" diff --git a/i18n/uk.po b/i18n/uk.po index 0697b82144..610b8d9f56 100644 --- a/i18n/uk.po +++ b/i18n/uk.po @@ -2,16 +2,16 @@ # Translators: # Wanda , 2021 # Nadiia , 2023 -# Viktor Varland , 2023 # Éva Tamási, 2023 # Philip Larsen Donnelly, 2023 +# Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Philip Larsen Donnelly, 2023\n" +"Last-Translator: Viktor Varland , 2023\n" "Language-Team: Ukrainian (https://app.transifex.com/hisp-uio/teams/100509/uk/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1143,6 +1143,33 @@ msgstr "Позначте для подальших дій" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Широта" + +msgid "Longitude" +msgstr "Довгота" + +msgid "Edit" +msgstr "Редагувати" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "" + +msgid "Delete polygon" +msgstr "" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "" + msgid "Enrollment date" msgstr "Дата реєстрації" @@ -1167,6 +1194,12 @@ msgstr "" msgid "Cancelled" msgstr "Скасовано" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1289,9 +1322,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "Редагувати" - msgid "tracked entity instance" msgstr "" @@ -1539,12 +1569,6 @@ msgstr "" msgid "Page {{currentPage}}" msgstr "" -msgid "Delete polygon" -msgstr "" - -msgid "Set area" -msgstr "" - msgid "Area on map saved" msgstr "" diff --git a/i18n/ur.po b/i18n/ur.po index c87c2e613a..458326829b 100644 --- a/i18n/ur.po +++ b/i18n/ur.po @@ -1,14 +1,14 @@ # # Translators: -# Viktor Varland , 2023 # Philip Larsen Donnelly, 2023 +# Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Philip Larsen Donnelly, 2023\n" +"Last-Translator: Viktor Varland , 2023\n" "Language-Team: Urdu (https://app.transifex.com/hisp-uio/teams/100509/ur/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -521,6 +521,9 @@ msgstr "" msgid "suggestions could not be retrieved" msgstr "" +msgid "No results found" +msgstr "کوئی نتیجہ نہیں ملا" + msgid "No items to display" msgstr "" @@ -939,9 +942,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "" -msgid "No results found" -msgstr "کوئی نتیجہ نہیں ملا" - msgid "An error occurred loading possible duplicates" msgstr "" @@ -1140,6 +1140,33 @@ msgstr "اپ کے لئے نشان زد کریں" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "طول" + +msgid "Longitude" +msgstr "لمبائی" + +msgid "Edit" +msgstr "ترمیم" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "سماج" + +msgid "Delete polygon" +msgstr "" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "" + msgid "Enrollment date" msgstr "اندراج کی تاریخ" @@ -1164,6 +1191,12 @@ msgstr "" msgid "Cancelled" msgstr "منسوخ" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1286,9 +1319,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "ترمیم" - msgid "tracked entity instance" msgstr "" @@ -1536,12 +1566,6 @@ msgstr "" msgid "Page {{currentPage}}" msgstr "" -msgid "Delete polygon" -msgstr "" - -msgid "Set area" -msgstr "" - msgid "Area on map saved" msgstr "" diff --git a/i18n/uz_UZ_Cyrl.po b/i18n/uz_UZ_Cyrl.po index 620b5591f9..0b7928980e 100644 --- a/i18n/uz_UZ_Cyrl.po +++ b/i18n/uz_UZ_Cyrl.po @@ -294,7 +294,7 @@ msgstr "" " қилинади." msgid "Yes, discard changes" -msgstr "" +msgstr "Ҳа, ўзгартиришлар бекор қилинсин" msgid "No, cancel" msgstr "Йўқ, бекор қилинг" @@ -1181,7 +1181,7 @@ msgid "Latitude" msgstr "Кенглик" msgid "Longitude" -msgstr "" +msgstr "Узунлик" msgid "Edit" msgstr "Таҳрирлаш" diff --git a/i18n/uz_UZ_Latn.po b/i18n/uz_UZ_Latn.po index 944b63b094..7e11d32a5a 100644 --- a/i18n/uz_UZ_Latn.po +++ b/i18n/uz_UZ_Latn.po @@ -541,6 +541,9 @@ msgstr "qidirish uchun yozishni boshlang" msgid "suggestions could not be retrieved" msgstr "takliflar qabul qilinmadi" +msgid "No results found" +msgstr "Hech qanday natija topilmadi" + msgid "No items to display" msgstr "Koʼrsatiladigan axborot yoʼq" @@ -963,9 +966,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "Boʼlishi mumkin boʼlgan nusxalar topildi" -msgid "No results found" -msgstr "Hech qanday natija topilmadi" - msgid "An error occurred loading possible duplicates" msgstr "" @@ -1168,6 +1168,33 @@ msgstr "Kuzatuv uchun belgilang" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Kenglik" + +msgid "Longitude" +msgstr "Kenglik" + +msgid "Edit" +msgstr "Tahrirlash" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Координаталар" + +msgid "Delete polygon" +msgstr "Poligon (koʼpburchak) ni oʼchirib tashlash" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "Hududni belgilang" + msgid "Enrollment date" msgstr "Qayd qilingan sana" @@ -1192,6 +1219,12 @@ msgstr "" msgid "Cancelled" msgstr "Bekor qilindi" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1314,9 +1347,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "Tahrirlash" - msgid "tracked entity instance" msgstr "kuzatilayotgan obʼekt namunasi" @@ -1565,12 +1595,6 @@ msgstr "Shu vaqtgacha" msgid "Page {{currentPage}}" msgstr "{{currentPage}} sahifasi" -msgid "Delete polygon" -msgstr "Poligon (koʼpburchak) ni oʼchirib tashlash" - -msgid "Set area" -msgstr "Hududni belgilang" - msgid "Area on map saved" msgstr "" diff --git a/i18n/vi.po b/i18n/vi.po index a2b56bfc1e..ac142f4ea7 100644 --- a/i18n/vi.po +++ b/i18n/vi.po @@ -2,15 +2,15 @@ # Translators: # Mai Nguyen , 2022 # Thuy Nguyen , 2023 -# Viktor Varland , 2023 # Philip Larsen Donnelly, 2023 +# Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Philip Larsen Donnelly, 2023\n" +"Last-Translator: Viktor Varland , 2023\n" "Language-Team: Vietnamese (https://app.transifex.com/hisp-uio/teams/100509/vi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -537,6 +537,9 @@ msgstr "bắt đầu nhập để tìm kiếm" msgid "suggestions could not be retrieved" msgstr "đề xuất không thể được truy xuất" +msgid "No results found" +msgstr "Không tìm thấy kết quả nào" + msgid "No items to display" msgstr "Không có mục để hiển thị" @@ -957,9 +960,6 @@ msgstr "" msgid "Possible duplicates found" msgstr "Có thể tìm thấy các bản sao" -msgid "No results found" -msgstr "Không tìm thấy kết quả nào" - msgid "An error occurred loading possible duplicates" msgstr "" @@ -1164,6 +1164,33 @@ msgstr "Đánh dấu để theo-dõi" msgid "Existing dates for auto-generated events will not be updated." msgstr "" +msgid "Latitude" +msgstr "Vĩ độ" + +msgid "Longitude" +msgstr "Kinh độ" + +msgid "Edit" +msgstr "Chỉnh sửa" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "Toạ độ" + +msgid "Delete polygon" +msgstr "Xóa đa giác" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "Đặt khu vực" + msgid "Enrollment date" msgstr "Ngày ghi vào" @@ -1188,6 +1215,12 @@ msgstr "" msgid "Cancelled" msgstr "Đã hủy" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "" @@ -1310,9 +1343,6 @@ msgstr "" msgid "{{TETName}} profile" msgstr "" -msgid "Edit" -msgstr "Chỉnh sửa" - msgid "tracked entity instance" msgstr "thực thể được theo dõi" @@ -1560,12 +1590,6 @@ msgstr "Đến " msgid "Page {{currentPage}}" msgstr "Trang {{currentPage}}" -msgid "Delete polygon" -msgstr "Xóa đa giác" - -msgid "Set area" -msgstr "Đặt khu vực" - msgid "Area on map saved" msgstr "" diff --git a/i18n/zh.po b/i18n/zh.po index 78121cdf22..5723afede3 100644 --- a/i18n/zh.po +++ b/i18n/zh.po @@ -1,16 +1,16 @@ # # Translators: # Philip Larsen Donnelly, 2022 -# Viktor Varland , 2023 -# 晓东 林 <13981924470@126.com>, 2023 # easylin , 2023 +# 晓东 林 <13981924470@126.com>, 2023 +# Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: easylin , 2023\n" +"Last-Translator: Viktor Varland , 2023\n" "Language-Team: Chinese (https://app.transifex.com/hisp-uio/teams/100509/zh/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1149,6 +1149,33 @@ msgstr "后续标记" msgid "Existing dates for auto-generated events will not be updated." msgstr "自动生成的事件的现有日期将不会更新。" +msgid "Latitude" +msgstr "维度" + +msgid "Longitude" +msgstr "经度" + +msgid "Edit" +msgstr "编辑" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "坐标" + +msgid "Delete polygon" +msgstr "删除多边形" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "设置区域" + msgid "Enrollment date" msgstr "报名日期" @@ -1173,6 +1200,12 @@ msgstr "最近更新的{{date}}" msgid "Cancelled" msgstr "已取消" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "关于本次报名的评论" @@ -1295,9 +1328,6 @@ msgstr "无法加载个人资料窗口小部件。请稍后再试" msgid "{{TETName}} profile" msgstr "{{TETName}} 基本信息" -msgid "Edit" -msgstr "编辑" - msgid "tracked entity instance" msgstr "跟踪的实体实例" @@ -1545,12 +1575,6 @@ msgstr "到时间" msgid "Page {{currentPage}}" msgstr "第{{currentPage}}页" -msgid "Delete polygon" -msgstr "删除多边形" - -msgid "Set area" -msgstr "设置区域" - msgid "Area on map saved" msgstr "地图上的区域已保存" diff --git a/i18n/zh_CN.po b/i18n/zh_CN.po index 215b2766d8..6ebfc4ee69 100644 --- a/i18n/zh_CN.po +++ b/i18n/zh_CN.po @@ -1,14 +1,14 @@ # # Translators: -# 晓东 林 <13981924470@126.com>, 2023 # easylin , 2023 +# 晓东 林 <13981924470@126.com>, 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: easylin , 2023\n" +"Last-Translator: 晓东 林 <13981924470@126.com>, 2023\n" "Language-Team: Chinese (China) (https://app.transifex.com/hisp-uio/teams/100509/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1147,6 +1147,33 @@ msgstr "后续标记" msgid "Existing dates for auto-generated events will not be updated." msgstr "自动生成的事件的现有日期将不会更新。" +msgid "Latitude" +msgstr "纬度" + +msgid "Longitude" +msgstr "经度" + +msgid "Edit" +msgstr "编辑" + +msgid "Set coordinates" +msgstr "" + +msgid "Coordinates" +msgstr "坐标" + +msgid "Delete polygon" +msgstr "删除多边形" + +msgid "Close without saving" +msgstr "" + +msgid "Finish drawing before saving" +msgstr "" + +msgid "Set area" +msgstr "设置区域" + msgid "Enrollment date" msgstr "报名日期" @@ -1171,6 +1198,12 @@ msgstr "最近更新的{{date}}" msgid "Cancelled" msgstr "已取消" +msgid "Add coordinates" +msgstr "" + +msgid "Add area" +msgstr "" + msgid "Comments about this enrollment" msgstr "关于本次报名的评论" @@ -1293,9 +1326,6 @@ msgstr "无法加载个人资料窗口小部件。请稍后再试" msgid "{{TETName}} profile" msgstr "{{TETName}}个人资料" -msgid "Edit" -msgstr "编辑" - msgid "tracked entity instance" msgstr "跟踪的实体实例" @@ -1543,12 +1573,6 @@ msgstr "到时间" msgid "Page {{currentPage}}" msgstr "第{{currentPage}}页" -msgid "Delete polygon" -msgstr "删除多边形" - -msgid "Set area" -msgstr "设置区域" - msgid "Area on map saved" msgstr "地图上的区域已保存" From efa835efd46051243ac0b457d6b403b2a15d0da4 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Sun, 3 Dec 2023 01:43:17 +0000 Subject: [PATCH 11/32] chore(release): cut 100.47.0 [skip release] # [100.47.0](https://github.com/dhis2/capture-app/compare/v100.46.1...v100.47.0) (2023-12-03) ### Bug Fixes * **translations:** sync translations from transifex (master) ([e20fb8c](https://github.com/dhis2/capture-app/commit/e20fb8c551aefb0546c5973dd87940d56e3018be)) ### Features * [DHIS2-16123] Add inheritable TEAs to Relationships ([#3464](https://github.com/dhis2/capture-app/issues/3464)) ([620b008](https://github.com/dhis2/capture-app/commit/620b00832da7c4951d6e905b40317dd0acca0aa6)) --- CHANGELOG.md | 12 ++++++++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b603a0b17..e6878dc55d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# [100.47.0](https://github.com/dhis2/capture-app/compare/v100.46.1...v100.47.0) (2023-12-03) + + +### Bug Fixes + +* **translations:** sync translations from transifex (master) ([e20fb8c](https://github.com/dhis2/capture-app/commit/e20fb8c551aefb0546c5973dd87940d56e3018be)) + + +### Features + +* [DHIS2-16123] Add inheritable TEAs to Relationships ([#3464](https://github.com/dhis2/capture-app/issues/3464)) ([620b008](https://github.com/dhis2/capture-app/commit/620b00832da7c4951d6e905b40317dd0acca0aa6)) + ## [100.46.1](https://github.com/dhis2/capture-app/compare/v100.46.0...v100.46.1) (2023-11-30) diff --git a/package.json b/package.json index 4648cadedc..a510d227de 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.46.1", + "version": "100.47.0", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.46.1", + "@dhis2/rules-engine-javascript": "100.47.0", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index ff1415cd4f..a894110539 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.46.1", + "version": "100.47.0", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From a47e429fc7148cf7c86c0b7865e87147cdbe1cfa Mon Sep 17 00:00:00 2001 From: Simona Domnisoru Date: Mon, 4 Dec 2023 08:32:29 +0100 Subject: [PATCH 12/32] test: [TECH-887] improve rules engine unit test coverage (#3462) --- packages/rules-engine/src/RulesEngine.js | 2 +- .../src/helpers/previousValueCheck.js | 2 +- .../rulesEffectsProcessor.js | 27 +- .../helpers/structureEvents.js | 6 +- ...eRuleEffectsForTrackerProgram.test.js.snap | 2 +- ...icableRuleEffectsForTrackerProgram.test.js | 150 +- ...licableRulesEffectsForEventProgram.test.js | 68 +- .../__tests__/postProcessRulesEffects.test.js | 211 ++ .../ruleEffectsForEventProgram.test.js | 2854 +++++++++++++++-- .../rulesEffectsForTrackerProgram.test.js | 889 ++++- .../rules/__tests__/rulesEngine.test.js | 717 +++++ 11 files changed, 4522 insertions(+), 406 deletions(-) create mode 100644 src/core_modules/capture-core/rules/__tests__/postProcessRulesEffects.test.js create mode 100644 src/core_modules/capture-core/rules/__tests__/rulesEngine.test.js diff --git a/packages/rules-engine/src/RulesEngine.js b/packages/rules-engine/src/RulesEngine.js index bbd6f279d1..d634f5d558 100644 --- a/packages/rules-engine/src/RulesEngine.js +++ b/packages/rules-engine/src/RulesEngine.js @@ -1,6 +1,6 @@ // @flow import log from 'loglevel'; -import { VariableService } from './services/VariableService/VariableService'; +import { VariableService } from './services/VariableService'; import { ValueProcessor } from './processors/ValueProcessor'; import { executeExpression } from './services/expressionService'; import { getD2Functions } from './d2Functions'; diff --git a/packages/rules-engine/src/helpers/previousValueCheck.js b/packages/rules-engine/src/helpers/previousValueCheck.js index 628900c6be..5745315d04 100644 --- a/packages/rules-engine/src/helpers/previousValueCheck.js +++ b/packages/rules-engine/src/helpers/previousValueCheck.js @@ -59,7 +59,7 @@ export const getOutputEffectsWithPreviousValueCheck = ({ onProcessValue: (value: any, type: $Values) => any, }) => outputEffects.reduce((acc, outputEffect) => { - if (formValues && outputEffect.targetDataType) { + if (formValues && Object.keys(formValues).length !== 0 && outputEffect.targetDataType) { const formValue = formValues[outputEffect.id]; const rawValue = mapByTargetDataTypes[outputEffect.targetDataType]({ dataElementId, diff --git a/packages/rules-engine/src/processors/rulesEffectsProcessor/rulesEffectsProcessor.js b/packages/rules-engine/src/processors/rulesEffectsProcessor/rulesEffectsProcessor.js index 15951dbc57..72cbd2f20f 100644 --- a/packages/rules-engine/src/processors/rulesEffectsProcessor/rulesEffectsProcessor.js +++ b/packages/rules-engine/src/processors/rulesEffectsProcessor/rulesEffectsProcessor.js @@ -296,26 +296,23 @@ export function getRulesEffectsProcessor( formValues, onProcessValue, }: { - effects: ?Array, + effects: Array, dataElements: ?DataElements, trackedEntityAttributes: ?TrackedEntityAttributes, formValues?: ?{ [key: string]: any }, onProcessValue: (value: any, type: $Values) => any, }): OutputEffects { - if (effects) { - return effects - .filter(({ action }) => mapActionsToProcessor[action]) - .flatMap(effect => mapActionsToProcessor[effect.action]( - effect, - dataElements, - trackedEntityAttributes, - formValues, - onProcessValue, - )) - // when mapActionsToProcessor function returns `null` we filter those value out. - .filter(keepTruthyValues => keepTruthyValues); - } - return []; + return effects + .filter(({ action }) => mapActionsToProcessor[action]) + .flatMap(effect => mapActionsToProcessor[effect.action]( + effect, + dataElements, + trackedEntityAttributes, + formValues, + onProcessValue, + )) + // when mapActionsToProcessor function returns `null` we filter those value out. + .filter(keepTruthyValues => keepTruthyValues); } return processRulesEffects; diff --git a/packages/rules-engine/src/services/VariableService/helpers/structureEvents.js b/packages/rules-engine/src/services/VariableService/helpers/structureEvents.js index e0e1422616..7c4fcab7f8 100644 --- a/packages/rules-engine/src/services/VariableService/helpers/structureEvents.js +++ b/packages/rules-engine/src/services/VariableService/helpers/structureEvents.js @@ -38,9 +38,9 @@ export const getStructureEvents = (compareDates: CompareDates) => { event.eventId !== currentEvent.eventId, ); - const events = [...otherEventsFiltered, currentEvent] - .sort(compareEvents); + const events = Object.keys(currentEvent).length !== 0 ? otherEventsFiltered.concat(currentEvent) : otherEventsFiltered; + const sortedEvents = events.sort(compareEvents); - return createEventsContainer(events); + return createEventsContainer(sortedEvents); }; }; diff --git a/src/core_modules/capture-core/rules/__tests__/__snapshots__/getApplicableRuleEffectsForTrackerProgram.test.js.snap b/src/core_modules/capture-core/rules/__tests__/__snapshots__/getApplicableRuleEffectsForTrackerProgram.test.js.snap index 2c73fac45b..f2fb347ece 100644 --- a/src/core_modules/capture-core/rules/__tests__/__snapshots__/getApplicableRuleEffectsForTrackerProgram.test.js.snap +++ b/src/core_modules/capture-core/rules/__tests__/__snapshots__/getApplicableRuleEffectsForTrackerProgram.test.js.snap @@ -125,7 +125,7 @@ Object { "trackedEntityAttributes": Object { "lZGmxYbs96q": Object { "id": "lZGmxYbs96q", - "optionSetId": undefined, + "optionSetId": "optionSet", "valueType": "DATE", }, "lZGmxYbs97q": Object { diff --git a/src/core_modules/capture-core/rules/__tests__/getApplicableRuleEffectsForTrackerProgram.test.js b/src/core_modules/capture-core/rules/__tests__/getApplicableRuleEffectsForTrackerProgram.test.js index 0ad48833c4..23e05892ba 100644 --- a/src/core_modules/capture-core/rules/__tests__/getApplicableRuleEffectsForTrackerProgram.test.js +++ b/src/core_modules/capture-core/rules/__tests__/getApplicableRuleEffectsForTrackerProgram.test.js @@ -1,3 +1,4 @@ +import { variableSourceTypes } from '@dhis2/rules-engine-javascript'; import { TrackerProgram, ProgramStage, @@ -10,24 +11,27 @@ import { } from '../../metaData'; import { getApplicableRuleEffectsForTrackerProgram } from '..'; -const mockGetProgramRuleEffects = jest.fn().mockImplementation(() => [{ - id: 'effectId', - type: 'DISPLAYTEXT', - message: 'display effect', -}]); +const mockGetProgramRuleEffects = jest.fn().mockImplementation(() => [ + { + id: 'effectId', + type: 'DISPLAYTEXT', + message: 'display effect', + }, +]); const mockOptionSet = new OptionSet('optionSet1', [new Option('option1', 'opt1')]); jest.mock('@dhis2/rules-engine-javascript/build/cjs/RulesEngine', () => ({ - RulesEngine: jest.fn().mockImplementation(() => - ({ getProgramRuleEffects: (...args) => mockGetProgramRuleEffects(...args) })), + RulesEngine: jest + .fn() + .mockImplementation(() => ({ getProgramRuleEffects: (...args) => mockGetProgramRuleEffects(...args) })), })); jest.mock('../../metaDataMemoryStores/constants/constants.store', () => ({ - constantsStore: ({ get: () => [{ id: 'constantId1', value: '1' }] }), + constantsStore: { get: () => [{ id: 'constantId1', value: '1' }] }, })); jest.mock('../../metaDataMemoryStores/optionSets/optionSets.store', () => ({ - optionSetStore: ({ get: () => [mockOptionSet] }), + optionSetStore: { get: () => [mockOptionSet] }, })); describe('getApplicableRuleEffectsForTrackerProgram', () => { @@ -46,20 +50,22 @@ describe('getApplicableRuleEffectsForTrackerProgram', () => { trackedEntityInstanceId: 'vCGpQAWG17I', }; - const otherEvents = [{ - da1Id: 'otherEventText', - dueDate: '2021-05-31T09:51:38.134', - enrollmentId: 'vVtmDlsu3me', - enrollmentStatus: 'ACTIVE', - eventDate: '2021-05-31T00:00:00.000', - eventId: 'BxGzDJK3JqN', - orgUnitId: 'DiszpKrYNg8', - orgUnitName: 'Ngelehun CHC', - programId: 'IpHINAT79UW', - programStageId: 'A03MvHHogjR', - status: 'ACTIVE', - trackedEntityInstanceId: 'vCGpQAWG17I', - }]; + const otherEvents = [ + { + da1Id: 'otherEventText', + dueDate: '2021-05-31T09:51:38.134', + enrollmentId: 'vVtmDlsu3me', + enrollmentStatus: 'ACTIVE', + eventDate: '2021-05-31T00:00:00.000', + eventId: 'BxGzDJK3JqN', + orgUnitId: 'DiszpKrYNg8', + orgUnitName: 'Ngelehun CHC', + programId: 'IpHINAT79UW', + programStageId: 'A03MvHHogjR', + status: 'ACTIVE', + trackedEntityInstanceId: 'vCGpQAWG17I', + }, + ]; const orgUnit = { id: 'DiszpKrYNg8', code: 'Ngelehun CHC' }; @@ -72,16 +78,18 @@ describe('getApplicableRuleEffectsForTrackerProgram', () => { const programStage = new ProgramStage((stage) => { stage.id = 'st1Id'; stage.name = 'stage1'; - stage.programRules = [{ - id: 'rule1Id', - name: 'rule1', - displayName: 'rule1', - priority: 1, - condition: 'true', - programId: 'IpHINAT79UW', - programStageId: 'st1Id', - programRuleActions: [], - }]; + stage.programRules = [ + { + id: 'rule1Id', + name: 'rule1', + displayName: 'rule1', + priority: 1, + condition: 'true', + programId: 'IpHINAT79UW', + programStageId: 'st1Id', + programRuleActions: [], + }, + ]; stage.stageForm = new RenderFoundation((foundation) => { const section = new Section((initSection) => { @@ -115,6 +123,7 @@ describe('getApplicableRuleEffectsForTrackerProgram', () => { element3.id = 'lZGmxYbs96q'; element3.name = 'SomeDate'; element3.type = dataElementTypes.DATE; + element3.optionSet = { id: 'optionSet', name: 'optionSet', code: 'optionSet' }; }), new DataElement((element4) => { element4.id = 'w75KJ2mc4zz'; @@ -129,7 +138,7 @@ describe('getApplicableRuleEffectsForTrackerProgram', () => { displayName: 'Test', id: 'PUQZWgmQ0jx', programId: 'IpHINAT79UW', - programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, useNameForOptionSet: true, }, { @@ -137,7 +146,7 @@ describe('getApplicableRuleEffectsForTrackerProgram', () => { displayName: 'apgarcomment', id: 'aKpfPKSRQnv', programId: 'IpHINAT79UW', - programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, useNameForOptionSet: true, }, { @@ -145,23 +154,27 @@ describe('getApplicableRuleEffectsForTrackerProgram', () => { displayName: 'apgarscore', id: 'g2GooOydipB', programId: 'IpHINAT79UW', - programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, useNameForOptionSet: true, }, ]; - initProgram.programRules = [{ - condition: 'true', - displayName: 'TestRule', - id: 'JJDQxgHuuL2', - programId: 'IpHINAT79UW', - programRuleActions: [{ - data: '#{Test}', - id: 'CQaifjkoFEU', - location: 'feedback', - programRuleActionType: 'DISPLAYTEXT', - }], - }]; + initProgram.programRules = [ + { + condition: 'true', + displayName: 'TestRule', + id: 'JJDQxgHuuL2', + programId: 'IpHINAT79UW', + programRuleActions: [ + { + data: '#{Test}', + id: 'CQaifjkoFEU', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + ], + }, + ]; }); const attributeValues = { @@ -210,16 +223,51 @@ describe('getApplicableRuleEffectsForTrackerProgram', () => { }); test('Flat result', () => { + const effects = getApplicableRuleEffectsForTrackerProgram( + { + program, + stage: programStage, + orgUnit, + currentEvent, + otherEvents, + attributeValues, + enrollmentData, + }, + true, + ); + + expect(Array.isArray(effects)).toBe(true); + }); + + test('RulesEngine called without programRules', () => { + const effects = getApplicableRuleEffectsForTrackerProgram({ + program: new TrackerProgram((initProgram) => { + initProgram.programRules = []; + }), + stage: new ProgramStage((stage) => { + stage.programRules = []; + }), + orgUnit, + currentEvent, + otherEvents, + attributeValues, + enrollmentData, + }); + + expect(effects).toStrictEqual([]); + }); + + test('currentEvent without a programStageId', () => { const effects = getApplicableRuleEffectsForTrackerProgram({ program, stage: programStage, orgUnit, - currentEvent, + currentEvent: {}, otherEvents, attributeValues, enrollmentData, - }, true); + }); - expect(Array.isArray(effects)).toBe(true); + expect(effects.DISPLAYTEXT).toBeDefined(); }); }); diff --git a/src/core_modules/capture-core/rules/__tests__/getApplicableRulesEffectsForEventProgram.test.js b/src/core_modules/capture-core/rules/__tests__/getApplicableRulesEffectsForEventProgram.test.js index 0fd9ac1510..7efadd5453 100644 --- a/src/core_modules/capture-core/rules/__tests__/getApplicableRulesEffectsForEventProgram.test.js +++ b/src/core_modules/capture-core/rules/__tests__/getApplicableRulesEffectsForEventProgram.test.js @@ -1,3 +1,4 @@ +import { variableSourceTypes } from '@dhis2/rules-engine-javascript'; import { EventProgram, ProgramStage, @@ -10,24 +11,27 @@ import { } from '../../metaData'; import { getApplicableRuleEffectsForEventProgram } from '..'; -const mockGetProgramRuleEffects = jest.fn().mockImplementation(() => [{ - id: 'effectId', - type: 'DISPLAYTEXT', - message: 'display effect', -}]); +const mockGetProgramRuleEffects = jest.fn().mockImplementation(() => [ + { + id: 'effectId', + type: 'DISPLAYTEXT', + message: 'display effect', + }, +]); const mockOptionSet = new OptionSet('optionSet1', [new Option('option1', 'opt1')]); jest.mock('@dhis2/rules-engine-javascript/build/cjs/RulesEngine', () => ({ - RulesEngine: jest.fn().mockImplementation(() => - ({ getProgramRuleEffects: (...args) => mockGetProgramRuleEffects(...args) })), + RulesEngine: jest + .fn() + .mockImplementation(() => ({ getProgramRuleEffects: (...args) => mockGetProgramRuleEffects(...args) })), })); jest.mock('../../metaDataMemoryStores/constants/constants.store', () => ({ - constantsStore: ({ get: () => [{ id: 'constantId1', value: '1' }] }), + constantsStore: { get: () => [{ id: 'constantId1', value: '1' }] }, })); jest.mock('../../metaDataMemoryStores/optionSets/optionSets.store', () => ({ - optionSetStore: ({ get: () => [mockOptionSet] }), + optionSetStore: { get: () => [mockOptionSet] }, })); describe('getApplicableRuleEffectsForEventProgram', () => { @@ -75,7 +79,7 @@ describe('getApplicableRuleEffectsForEventProgram', () => { displayName: 'Test', id: 'PUQZWgmQ0jx', programId: 'IpHINAT79UW', - programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, useNameForOptionSet: true, }, { @@ -83,7 +87,7 @@ describe('getApplicableRuleEffectsForEventProgram', () => { displayName: 'apgarcomment', id: 'aKpfPKSRQnv', programId: 'IpHINAT79UW', - programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, useNameForOptionSet: true, }, { @@ -91,23 +95,27 @@ describe('getApplicableRuleEffectsForEventProgram', () => { displayName: 'apgarscore', id: 'g2GooOydipB', programId: 'IpHINAT79UW', - programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, useNameForOptionSet: true, }, ]; - initProgram.programRules = [{ - condition: 'true', - displayName: 'TestRule', - id: 'JJDQxgHuuL2', - programId: 'IpHINAT79UW', - programRuleActions: [{ - data: '#{Test}', - id: 'CQaifjkoFEU', - location: 'feedback', - programRuleActionType: 'DISPLAYTEXT', - }], - }]; + initProgram.programRules = [ + { + condition: 'true', + displayName: 'TestRule', + id: 'JJDQxgHuuL2', + programId: 'IpHINAT79UW', + programRuleActions: [ + { + data: '#{Test}', + id: 'CQaifjkoFEU', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + ], + }, + ]; }); test('RulesEngine called with computed arguments from getApplicableRuleEffectsForEventProgram', () => { @@ -139,4 +147,16 @@ describe('getApplicableRuleEffectsForEventProgram', () => { expect(effects.DISPLAYTEXT).toBeDefined(); }); + + test('RulesEngine called without programRules', () => { + const effects = getApplicableRuleEffectsForEventProgram({ + program: new EventProgram((initProgram) => { + initProgram.programRules = []; + }), + orgUnit, + currentEvent, + }); + + expect(effects).toStrictEqual([]); + }); }); diff --git a/src/core_modules/capture-core/rules/__tests__/postProcessRulesEffects.test.js b/src/core_modules/capture-core/rules/__tests__/postProcessRulesEffects.test.js new file mode 100644 index 0000000000..6792dc777f --- /dev/null +++ b/src/core_modules/capture-core/rules/__tests__/postProcessRulesEffects.test.js @@ -0,0 +1,211 @@ +import { postProcessRulesEffects } from '../index'; +import { RenderFoundation, Section, DataElement, dataElementTypes } from '../../metaData'; + +test('Post process rules effects', () => { + // given + const rulesEffects = [ + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Eeb7Ixr4Pv6', message: 'd2:floor((5+5) / 2) = 5' }, + }, + { type: 'HIDEPROGRAMSTAGE', id: 'PUZaKR0Jh2k' }, + { id: 'SWfdBhglX0fk', type: 'HIDESECTION' }, + { id: 'w75KJ2mc4zz', type: 'ASSIGN', value: 'true' }, + { id: 'wasdJ2mc4zz', type: 'ASSIGN', value: 'true' }, + { + id: 'w75KJ2mc4zz', + message: ' true', + type: 'ERRORONCOMPLETE', + }, + { + id: 'w75KJ2mc4zz', + message: ' true', + type: 'WARNINGONCOMPLETE', + }, + { + id: 'w75KJ2mc4zz', + type: 'SETMANDATORYFIELD', + }, + { + content: undefined, + id: 'zDhUuAYrxNC', + targetDataType: 'trackedEntityAttribute', + type: 'HIDEFIELD', + hadValue: true, + name: undefined, + }, + { + content: undefined, + id: 'unknown', + type: 'HIDEFIELD', + }, + { + displayKeyValuePair: { + id: 'khy8GmlwpgZ', + key: "d2:weeksBetween('2020-01-28', V{unknown} ) = ", + value: '', + }, + id: 'feedback', + type: 'DISPLAYKEYVALUEPAIR', + }, + ]; + + const foundation = new RenderFoundation(() => {}); + const section1 = new Section((initSection) => { + initSection.id = 's1Id'; + initSection.name = 'section1'; + const dataElement1 = new DataElement((o) => { + o.id = 'w75KJ2mc4zz'; + o.name = 'dataElement1'; + o.type = dataElementTypes.TEXT; + o.optionSet = { + id: 'optionSet', + name: 'optionSet', + code: 'optionSet', + options: [{ option: { value: false } }], + }; + }); + + const dataElement2 = new DataElement((o) => { + o.id = 'wasdJ2mc4zz'; + o.name = 'dataElement1'; + o.type = dataElementTypes.NUMBER; + o.compulsory = true; + }); + initSection.addElement(dataElement1); + initSection.addElement(dataElement2); + }); + + const section2 = new Section((initSection) => { + initSection.id = 'SWfdBhglX0fk'; + initSection.name = 'section2'; + const dataElement = new DataElement((o) => { + o.id = 'da1Id'; + o.name = 'dataElement1'; + o.type = dataElementTypes.TEXT; + }); + + initSection.addElement(dataElement); + }); + + foundation.addSection(section1); + foundation.addSection(section2); + + // when + const processedRulesEffects = postProcessRulesEffects(rulesEffects, foundation); + + // then + expect(processedRulesEffects).toEqual([ + { + displayText: { + id: 'Eeb7Ixr4Pv6', + message: 'd2:floor((5+5) / 2) = 5', + }, + id: 'feedback', + type: 'DISPLAYTEXT', + }, + { + id: 'PUZaKR0Jh2k', + type: 'HIDEPROGRAMSTAGE', + }, + { + id: 'w75KJ2mc4zz', + message: ' true', + type: 'ERRORONCOMPLETE', + }, + { + id: 'w75KJ2mc4zz', + message: ' true', + type: 'WARNINGONCOMPLETE', + }, + { + id: 'w75KJ2mc4zz', + type: 'SETMANDATORYFIELD', + }, + { + displayKeyValuePair: { + id: 'khy8GmlwpgZ', + key: "d2:weeksBetween('2020-01-28', V{unknown} ) = ", + value: '', + }, + id: 'feedback', + type: 'DISPLAYKEYVALUEPAIR', + }, + { + content: undefined, + id: 'unknown', + type: 'HIDEFIELD', + }, + { + id: 'da1Id', + type: 'HIDEFIELD', + }, + { + id: 'unknown', + type: 'ASSIGN', + value: null, + }, + { + id: 'w75KJ2mc4zz', + type: 'ASSIGN', + value: null, + }, + { + id: 'wasdJ2mc4zz', + type: 'ASSIGN', + value: 'true', + }, + ]); +}); + +test('the rules effects are not defined', () => { + // given + + const foundation = new RenderFoundation(() => {}); + const section1 = new Section((initSection) => { + initSection.id = 's1Id'; + initSection.name = 'section1'; + const dataElement1 = new DataElement((o) => { + o.id = 'da1Id'; + o.name = 'dataElement1'; + o.type = dataElementTypes.TEXT; + }); + + initSection.addElement(dataElement1); + }); + + foundation.addSection(section1); + + // when + const processedRulesEffects = postProcessRulesEffects(undefined, foundation); + + // then + expect(processedRulesEffects).toEqual([]); +}); + +test('HIDESECTION effect sectionId do not match the formFoundation sectionId', () => { + // given + const rulesEffects = [{ id: 'SWfdBhglX0fk', type: 'HIDESECTION' }]; + + const foundation = new RenderFoundation(() => {}); + const section1 = new Section((initSection) => { + initSection.id = 's1Id'; + initSection.name = 'section1'; + const dataElement1 = new DataElement((o) => { + o.id = 'da1Id'; + o.name = 'dataElement1'; + o.type = dataElementTypes.TEXT; + }); + + initSection.addElement(dataElement1); + }); + + foundation.addSection(section1); + + // when + const processedRulesEffects = postProcessRulesEffects(rulesEffects, foundation); + + // then + expect(processedRulesEffects).toEqual([]); +}); diff --git a/src/core_modules/capture-core/rules/__tests__/ruleEffectsForEventProgram.test.js b/src/core_modules/capture-core/rules/__tests__/ruleEffectsForEventProgram.test.js index 8fd6054d3c..215b2a8ea0 100644 --- a/src/core_modules/capture-core/rules/__tests__/ruleEffectsForEventProgram.test.js +++ b/src/core_modules/capture-core/rules/__tests__/ruleEffectsForEventProgram.test.js @@ -1,19 +1,95 @@ -import { rulesEngineEffectTargetDataTypes } from '@dhis2/rules-engine-javascript'; +import { rulesEngineEffectTargetDataTypes, variableSourceTypes } from '@dhis2/rules-engine-javascript'; import { rulesEngine } from '../rulesEngine'; +import { systemSettingsStore } from '../../metaDataMemoryStores'; describe('Event Event rules engine', () => { // these variables are shared between each test - const constants = [{ id: 'Gfd3ppDfq8E', displayName: 'Commodity ordering overhead', value: 5 }, { id: 'bCqvfPR02Im', displayName: 'Pi', value: 3.14 }]; - const dataElementsInProgram = { sWoqcoByYmD: { id: 'sWoqcoByYmD', valueType: 'BOOLEAN' }, Ok9OQpitjQr: { id: 'Ok9OQpitjQr', valueType: 'BOOLEAN' }, vANAXwtLwcT: { id: 'vANAXwtLwcT', valueType: 'NUMBER' } }; - const programRules = [{ id: 'GC4gpdoSD4r', condition: '#{hemoglobin} < 9', description: 'Show warning if hemoglobin is dangerously low', displayName: 'Hemoglobin warning', programId: 'lxAQ7Zs9VYR', programRuleActions: [{ id: 'suS9GnraCx1', content: 'Hemoglobin value lower than normal', displayContent: 'Hemoglobin value lower than normal', dataElementId: 'vANAXwtLwcT', programRuleActionType: 'SHOWWARNING' }] }, { id: 'dahuKlP7jR2', condition: '#{hemoglobin} > 99', description: 'Show error for hemoglobin value higher than 99', displayName: 'Show error for high hemoglobin value', programId: 'lxAQ7Zs9VYR', programRuleActions: [{ id: 'UUwZWS8uirn', content: 'The hemoglobin value cannot be above 99', displayContent: 'The hemoglobin value cannot be above 99', dataElementId: 'vANAXwtLwcT', programRuleActionType: 'SHOWERROR' }] }, { id: 'xOe5qCzRS0Y', condition: '!#{womanSmoking} ', description: 'Hide smoking cessation councelling dataelement unless patient is smoking', displayName: 'Hide smoking cessation councelling', programId: 'lxAQ7Zs9VYR', programRuleActions: [{ id: 'hwgyO59SSxu', dataElementId: 'Ok9OQpitjQr', programRuleActionType: 'HIDEFIELD' }] }]; - const programRuleVariables = [{ id: 'Z92dJO9gIje', dataElementId: 'sWoqcoByYmD', displayName: 'womanSmoking', programId: 'lxAQ7Zs9VYR', programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', useNameForOptionSet: true }, { id: 'omrL0gtPpDL', dataElementId: 'vANAXwtLwcT', displayName: 'hemoglobin', programId: 'lxAQ7Zs9VYR', programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', useNameForOptionSet: true }]; + const constants = [ + { id: 'Gfd3ppDfq8E', displayName: 'Commodity ordering overhead', value: 5 }, + { id: 'bCqvfPR02Im', displayName: 'Pi', value: 3.14 }, + ]; + const dataElementsInProgram = { + sWoqcoByYmD: { id: 'sWoqcoByYmD', valueType: 'BOOLEAN' }, + Ok9OQpitjQr: { id: 'Ok9OQpitjQr', valueType: 'BOOLEAN' }, + vANAXwtLwcT: { id: 'vANAXwtLwcT', valueType: 'NUMBER' }, + }; + const programRules = [ + { + id: 'GC4gpdoSD4r', + condition: '#{hemoglobin} < 9', + description: 'Show warning if hemoglobin is dangerously low', + displayName: 'Hemoglobin warning', + programId: 'lxAQ7Zs9VYR', + programRuleActions: [ + { + id: 'suS9GnraCx1', + content: 'Hemoglobin value lower than normal', + displayContent: 'Hemoglobin value lower than normal', + dataElementId: 'vANAXwtLwcT', + programRuleActionType: 'SHOWWARNING', + }, + ], + }, + { + id: 'dahuKlP7jR2', + condition: '#{hemoglobin} > 99', + description: 'Show error for hemoglobin value higher than 99', + displayName: 'Show error for high hemoglobin value', + programId: 'lxAQ7Zs9VYR', + programRuleActions: [ + { + id: 'UUwZWS8uirn', + content: 'The hemoglobin value cannot be above 99', + displayContent: 'The hemoglobin value cannot be above 99', + dataElementId: 'vANAXwtLwcT', + programRuleActionType: 'SHOWERROR', + }, + ], + }, + { + id: 'xOe5qCzRS0Y', + condition: '!#{womanSmoking} ', + description: 'Hide smoking cessation councelling dataelement unless patient is smoking', + displayName: 'Hide smoking cessation councelling', + programId: 'lxAQ7Zs9VYR', + programRuleActions: [ + { id: 'hwgyO59SSxu', dataElementId: 'Ok9OQpitjQr', programRuleActionType: 'HIDEFIELD' }, + ], + }, + ]; + const programRuleVariables = [ + { + id: 'Z92dJO9gIje', + dataElementId: 'sWoqcoByYmD', + displayName: 'womanSmoking', + programId: 'lxAQ7Zs9VYR', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, + useNameForOptionSet: true, + }, + { + id: 'omrL0gtPpDL', + dataElementId: 'vANAXwtLwcT', + displayName: 'hemoglobin', + programId: 'lxAQ7Zs9VYR', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, + useNameForOptionSet: true, + }, + ]; const orgUnit = { id: 'DiszpKrYNg8', name: 'Ngelehun CHC' }; const optionSets = {}; describe.each([ [ { vANAXwtLwcT: 0 }, - [{ id: 'vANAXwtLwcT', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, message: 'Hemoglobin value lower than normal ', type: 'SHOWWARNING' }, { id: 'Ok9OQpitjQr', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, type: 'HIDEFIELD' }], + [ + { + id: 'vANAXwtLwcT', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + message: 'Hemoglobin value lower than normal ', + type: 'SHOWWARNING', + }, + { id: 'Ok9OQpitjQr', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, type: 'HIDEFIELD' }, + ], ], [ { vANAXwtLwcT: 9 }, @@ -25,7 +101,15 @@ describe('Event Event rules engine', () => { ], [ { vANAXwtLwcT: 100 }, - [{ id: 'vANAXwtLwcT', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, message: 'The hemoglobin value cannot be above 99 ', type: 'SHOWERROR' }, { id: 'Ok9OQpitjQr', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, type: 'HIDEFIELD' }], + [ + { + id: 'vANAXwtLwcT', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + message: 'The hemoglobin value cannot be above 99 ', + type: 'SHOWERROR', + }, + { id: 'Ok9OQpitjQr', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, type: 'HIDEFIELD' }, + ], ], ])('where value needs to >= 9 and <= 99', (currentEvent, expected) => { test(`and given value(s): ${JSON.stringify(currentEvent)}`, () => { @@ -44,11 +128,26 @@ describe('Event Event rules engine', () => { describe.each([ [ { sWoqcoByYmD: true }, - [{ id: 'vANAXwtLwcT', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, message: 'Hemoglobin value lower than normal ', type: 'SHOWWARNING' }], + [ + { + id: 'vANAXwtLwcT', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + message: 'Hemoglobin value lower than normal ', + type: 'SHOWWARNING', + }, + ], ], [ { sWoqcoByYmD: false }, - [{ id: 'vANAXwtLwcT', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, message: 'Hemoglobin value lower than normal ', type: 'SHOWWARNING' }, { id: 'Ok9OQpitjQr', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, type: 'HIDEFIELD' }], + [ + { + id: 'vANAXwtLwcT', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + message: 'Hemoglobin value lower than normal ', + type: 'SHOWWARNING', + }, + { id: 'Ok9OQpitjQr', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, type: 'HIDEFIELD' }, + ], ], ])('where field is hidden regarding a boolean value', (currentEvent, expected) => { test(`and given value(s): ${JSON.stringify(currentEvent)}`, () => { @@ -67,25 +166,138 @@ describe('Event Event rules engine', () => { describe('Event rules engine', () => { // these variables are shared between each test - const constants = [{ id: 'Gfd3ppDfq8E', displayName: 'Commodity ordering overhead', value: 5 }, { id: 'bCqvfPR02Im', displayName: 'Pi', value: 3.14 }]; - const dataElementsInProgram = { oZg33kd9taw: { id: 'oZg33kd9taw', valueType: 'TEXT', optionSetId: 'pC3N9N77UmT' }, SWfdB5lX0fk: { id: 'SWfdB5lX0fk', valueType: 'BOOLEAN', optionSetId: undefined }, qrur9Dvnyt5: { id: 'qrur9Dvnyt5', valueType: 'INTEGER', optionSetId: undefined }, GieVkTxp4HH: { id: 'GieVkTxp4HH', valueType: 'NUMBER', optionSetId: undefined }, vV9UWAZohSf: { id: 'vV9UWAZohSf', valueType: 'INTEGER_POSITIVE', optionSetId: undefined }, eMyVanycQSC: { id: 'eMyVanycQSC', valueType: 'DATE', optionSetId: undefined }, K6uUAvq500H: { id: 'K6uUAvq500H', valueType: 'TEXT', optionSetId: 'eUZ79clX7y1' }, msodh3rEMJa: { id: 'msodh3rEMJa', valueType: 'DATE', optionSetId: undefined }, S33cRBsnXPo: { id: 'S33cRBsnXPo', valueType: 'ORGANISATION_UNIT', optionSetId: undefined }, fWIAEtYVEGk: { id: 'fWIAEtYVEGk', valueType: 'TEXT', optionSetId: 'iDFPKpFTiVw' }, ulD2zW0TIy2: { id: 'ulD2zW0TIy2', valueType: 'FILE_RESOURCE' } }; - const programRules = [{ id: 'fd3wL1quxGb', condition: "#{gender} == 'Male'", description: 'Hide pregnant if gender is male', displayName: 'Hide pregnant if gender is male', programId: 'eBAyeGv0exc', programRuleActions: [{ id: 'IrmpncBsypT', dataElementId: 'SWfdB5lX0fk', programRuleActionType: 'HIDEFIELD', programStageSectionId: 'd7ZILSbPgYh' }] }, { id: 'x7PaHGvgWY2', condition: 'true', description: 'Body Mass Index. Weight in kg / height in m square.', displayName: 'BMI', programId: 'eBAyeGv0exc', programRuleActions: [{ id: 'x7PaHGvgWY2', content: 'BMI', displayContent: 'BMI', data: '#{Zj7UnCAulEk.vV9UWAZohSf}/((#{Zj7UnCAulEk.GieVkTxp4HH}/100)*(#{Zj7UnCAulEk.GieVkTxp4HH}/100))', programRuleActionType: 'DISPLAYKEYVALUEPAIR', location: 'indicators' }] }]; - const programRuleVariables = [{ id: 'RycV5uDi66i', dataElementId: 'qrur9Dvnyt5', displayName: 'age', programId: 'eBAyeGv0exc', programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', useNameForOptionSet: true }, { id: 'zINGRka3g9N', dataElementId: 'oZg33kd9taw', displayName: 'gender', programId: 'eBAyeGv0exc', programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', useNameForOptionSet: true }, { id: 'Zj7UnCAulEk.vV9UWAZohSf', displayName: 'Zj7UnCAulEk.vV9UWAZohSf', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', dataElementId: 'vV9UWAZohSf', programId: 'eBAyeGv0exc' }, { id: 'Zj7UnCAulEk.GieVkTxp4HH', displayName: 'Zj7UnCAulEk.GieVkTxp4HH', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', dataElementId: 'GieVkTxp4HH', programId: 'eBAyeGv0exc' }, { id: 'Zj7UnCAulEk.GieVkTxp4HH', displayName: 'Zj7UnCAulEk.GieVkTxp4HH', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', dataElementId: 'GieVkTxp4HH', programId: 'eBAyeGv0exc' }]; + const constants = [ + { id: 'Gfd3ppDfq8E', displayName: 'Commodity ordering overhead', value: 5 }, + { id: 'bCqvfPR02Im', displayName: 'Pi', value: 3.14 }, + ]; + const dataElementsInProgram = { + oZg33kd9taw: { id: 'oZg33kd9taw', valueType: 'TEXT', optionSetId: 'pC3N9N77UmT' }, + SWfdB5lX0fk: { id: 'SWfdB5lX0fk', valueType: 'TRUE_ONLY', optionSetId: undefined }, + qrur9Dvnyt5: { id: 'qrur9Dvnyt5', valueType: 'INTEGER', optionSetId: undefined }, + GieVkTxp4HH: { id: 'GieVkTxp4HH', valueType: 'NUMBER', optionSetId: undefined }, + vV9UWAZohSf: { id: 'vV9UWAZohSf', valueType: 'INTEGER_POSITIVE', optionSetId: undefined }, + eMyVanycQSC: { id: 'eMyVanycQSC', valueType: 'DATE', optionSetId: undefined }, + K6uUAvq500H: { id: 'K6uUAvq500H', valueType: 'TEXT', optionSetId: 'eUZ79clX7y1' }, + msodh3rEMJa: { id: 'msodh3rEMJa', valueType: 'DATE', optionSetId: undefined }, + S33cRBsnXPo: { id: 'S33cRBsnXPo', valueType: 'ORGANISATION_UNIT', optionSetId: undefined }, + fWIAEtYVEGk: { id: 'fWIAEtYVEGk', valueType: 'TEXT', optionSetId: 'iDFPKpFTiVw' }, + ulD2zW0TIy2: { id: 'ulD2zW0TIy2', valueType: 'FILE_RESOURCE' }, + }; + const programRules = [ + { + id: 'fd3wL1quxGb', + condition: "#{gender} == 'Male'", + description: 'Hide pregnant if gender is male', + displayName: 'Hide pregnant if gender is male', + programId: 'eBAyeGv0exc', + programRuleActions: [ + { + id: 'IrmpncBsypT', + dataElementId: 'SWfdB5lX0fk', + programRuleActionType: 'HIDEFIELD', + programStageSectionId: 'd7ZILSbPgYh', + }, + ], + }, + { + id: 'x7PaHGvgWY2', + condition: 'true', + description: 'Body Mass Index. Weight in kg / height in m square.', + displayName: 'BMI', + programId: 'eBAyeGv0exc', + programRuleActions: [ + { + id: 'x7PaHGvgWY2', + content: 'BMI', + displayContent: 'BMI', + data: '#{Zj7UnCAulEk.vV9UWAZohSf}/((#{Zj7UnCAulEk.GieVkTxp4HH}/100)*(#{Zj7UnCAulEk.GieVkTxp4HH}/100))', + programRuleActionType: 'DISPLAYKEYVALUEPAIR', + location: 'indicators', + }, + ], + }, + ]; + const programRuleVariables = [ + { + id: 'RycV5uDi66i', + dataElementId: 'qrur9Dvnyt5', + displayName: 'age', + programId: 'eBAyeGv0exc', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, + useNameForOptionSet: true, + }, + { + id: 'zINGRka3g9N', + dataElementId: 'oZg33kd9taw', + displayName: 'gender', + programId: 'eBAyeGv0exc', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, + useNameForOptionSet: true, + }, + { + id: 'Zj7UnCAulEk.vV9UWAZohSf', + displayName: 'Zj7UnCAulEk.vV9UWAZohSf', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + dataElementId: 'vV9UWAZohSf', + programId: 'eBAyeGv0exc', + }, + { + id: 'Zj7UnCAulEk.GieVkTxp4HH', + displayName: 'Zj7UnCAulEk.GieVkTxp4HH', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + dataElementId: 'GieVkTxp4HH', + programId: 'eBAyeGv0exc', + }, + { + id: 'Zj7UnCAulEk.GieVkTxp4HH', + displayName: 'Zj7UnCAulEk.GieVkTxp4HH', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + dataElementId: 'GieVkTxp4HH', + programId: 'eBAyeGv0exc', + }, + ]; const orgUnit = { id: 'DiszpKrYNg8', name: 'Ngelehun CHC' }; - const optionSets = { pC3N9N77UmT: { id: 'pC3N9N77UmT', displayName: 'Gender', version: 0, valueType: 'TEXT', options: [{ id: 'rBvjJYbMCVx', displayName: 'Male', code: 'Male', translations: [] }, { id: 'Mnp3oXrpAbK', displayName: 'Female', code: 'Female', translations: [] }] } }; + const optionSets = { + pC3N9N77UmT: { + id: 'pC3N9N77UmT', + displayName: 'Gender', + version: 0, + valueType: 'TEXT', + options: undefined, + }, + }; describe.each([ [ { oZg33kd9taw: 'Female', SWfdB5lX0fk: null }, - [{ displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, id: 'indicators', type: 'DISPLAYKEYVALUEPAIR' }], + [ + { + displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, + id: 'indicators', + type: 'DISPLAYKEYVALUEPAIR', + }, + ], ], [ { oZg33kd9taw: 'Male', SWfdB5lX0fk: null }, - [{ id: 'SWfdB5lX0fk', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, type: 'HIDEFIELD' }, { displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, id: 'indicators', type: 'DISPLAYKEYVALUEPAIR' }], + [ + { id: 'SWfdB5lX0fk', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, type: 'HIDEFIELD' }, + { + displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, + id: 'indicators', + type: 'DISPLAYKEYVALUEPAIR', + }, + ], ], [ { oZg33kd9taw: null, SWfdB5lX0fk: null }, - [{ displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, id: 'indicators', type: 'DISPLAYKEYVALUEPAIR' }], + [ + { + displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, + id: 'indicators', + type: 'DISPLAYKEYVALUEPAIR', + }, + ], ], ])('where field is hidden regarding the gender of the event', (currentEvent, expected) => { test(`and given value(s): ${JSON.stringify(currentEvent)}`, () => { @@ -104,35 +316,83 @@ describe('Event rules engine', () => { describe.each([ [ { qrur9Dvnyt5: null, GieVkTxp4HH: null, vV9UWAZohSf: null }, - [{ displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, id: 'indicators', type: 'DISPLAYKEYVALUEPAIR' }], + [ + { + displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, + id: 'indicators', + type: 'DISPLAYKEYVALUEPAIR', + }, + ], ], [ { qrur9Dvnyt5: null, GieVkTxp4HH: null, vV9UWAZohSf: 85 }, - [{ displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, id: 'indicators', type: 'DISPLAYKEYVALUEPAIR' }], + [ + { + displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, + id: 'indicators', + type: 'DISPLAYKEYVALUEPAIR', + }, + ], ], [ { qrur9Dvnyt5: null, GieVkTxp4HH: 180, vV9UWAZohSf: null }, - [{ displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '0' }, id: 'indicators', type: 'DISPLAYKEYVALUEPAIR' }], + [ + { + displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '0' }, + id: 'indicators', + type: 'DISPLAYKEYVALUEPAIR', + }, + ], ], [ { qrur9Dvnyt5: null, GieVkTxp4HH: 180, vV9UWAZohSf: 85 }, - [{ displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '26.234567901234566' }, id: 'indicators', type: 'DISPLAYKEYVALUEPAIR' }], + [ + { + displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '26.234567901234566' }, + id: 'indicators', + type: 'DISPLAYKEYVALUEPAIR', + }, + ], ], [ { qrur9Dvnyt5: 40, GieVkTxp4HH: null, vV9UWAZohSf: null }, - [{ displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, id: 'indicators', type: 'DISPLAYKEYVALUEPAIR' }], + [ + { + displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, + id: 'indicators', + type: 'DISPLAYKEYVALUEPAIR', + }, + ], ], [ { qrur9Dvnyt5: 40, GieVkTxp4HH: null, vV9UWAZohSf: 85 }, - [{ displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, id: 'indicators', type: 'DISPLAYKEYVALUEPAIR' }], + [ + { + displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '' }, + id: 'indicators', + type: 'DISPLAYKEYVALUEPAIR', + }, + ], ], [ { qrur9Dvnyt5: 40, GieVkTxp4HH: 180, vV9UWAZohSf: null }, - [{ displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '0' }, id: 'indicators', type: 'DISPLAYKEYVALUEPAIR' }], + [ + { + displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '0' }, + id: 'indicators', + type: 'DISPLAYKEYVALUEPAIR', + }, + ], ], [ { qrur9Dvnyt5: 40, GieVkTxp4HH: 180, vV9UWAZohSf: 85 }, - [{ displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '26.234567901234566' }, id: 'indicators', type: 'DISPLAYKEYVALUEPAIR' }], + [ + { + displayKeyValuePair: { id: 'x7PaHGvgWY2', key: 'BMI', value: '26.234567901234566' }, + id: 'indicators', + type: 'DISPLAYKEYVALUEPAIR', + }, + ], ], ])('where BMI is calculated', (currentEvent, expected) => { test(`and given value(s): ${JSON.stringify(currentEvent)}`, () => { @@ -151,14 +411,503 @@ describe('Event rules engine', () => { describe('Event rules engine', () => { // these variables are shared between each test - const constants = [{ id: 'Gfd3ppDfq8E', displayName: 'Commodity ordering overhead', value: 5 }, { id: 'bCqvfPR02Im', displayName: 'Pi', value: 3.14 }]; - const dataElementsInProgram = { dyfYIsTFTjG: { id: 'dyfYIsTFTjG', valueType: 'TEXT' }, XOaXLWuhKzV: { id: 'XOaXLWuhKzV', valueType: 'TEXT', optionSetId: 'WDUwjiW2rGH' }, AtFlciXnstG: { id: 'AtFlciXnstG', valueType: 'INTEGER_ZERO_OR_POSITIVE' }, JGnHr6WI3AY: { id: 'JGnHr6WI3AY', valueType: 'TEXT', optionSetId: 'L6eMZDJkCwX' }, s3eoonJ8OJb: { id: 's3eoonJ8OJb', valueType: 'DATE' }, gktroFPckdr: { id: 'gktroFPckdr', valueType: 'TEXT', optionSetId: 'UYDsNdpo2BU' }, QQLXTXVidW2: { id: 'QQLXTXVidW2', valueType: 'TEXT', optionSetId: 'L6eMZDJkCwX' }, ovY6E8BSdto: { id: 'ovY6E8BSdto', valueType: 'TEXT', optionSetId: 'dsgBmIZ0Yrq' }, Z5z8vFQy0w0: { id: 'Z5z8vFQy0w0', valueType: 'TEXT' }, TzqawmlPkI5: { id: 'TzqawmlPkI5', valueType: 'TEXT', optionSetId: 'L6eMZDJkCwX' }, f8j4XDEozvj: { id: 'f8j4XDEozvj', valueType: 'TEXT', optionSetId: 'xD9QOIvNAjw' }, jBBkFuPKctq: { id: 'jBBkFuPKctq', valueType: 'TEXT', optionSetId: 'T9zjyaIkRqH' }, A4Fg6jgWauf: { id: 'A4Fg6jgWauf', valueType: 'TEXT', optionSetId: 'w1vUkxq8IOl' }, CUbZcLm9LyN: { id: 'CUbZcLm9LyN', valueType: 'TEXT', optionSetId: 'L6eMZDJkCwX' }, p8htbyJHydl: { id: 'p8htbyJHydl', valueType: 'TEXT', optionSetId: 'L6eMZDJkCwX' }, SbXES4EPgqP: { id: 'SbXES4EPgqP', valueType: 'NUMBER' }, bOYWVEBaWy6: { id: 'bOYWVEBaWy6', valueType: 'TEXT', optionSetId: 'qI4cs9ocBwn' }, PFXeJV8d7ja: { id: 'PFXeJV8d7ja', valueType: 'DATE' } }; - const programRules = [{ id: 'DOz4wl8ErDD', condition: 'true', description: 'Hide Irrelevant Test Result Options', displayName: 'Hide Test Result Options', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'XuM1JizlcF1', dataElementId: 'ovY6E8BSdto', programRuleActionType: 'HIDEOPTION', optionId: 'MkeWrqeqZXL' }, { id: 'FRfTFXSwKDU', dataElementId: 'ovY6E8BSdto', programRuleActionType: 'HIDEOPTION', optionId: 'fPV0gQ8ds6D' }] }, { id: 'DtfaG1TgyZk', condition: "(d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'No') ||\n(d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'Yes' && #{TEST_RESULT} == 'Inconclusive')", description: "Automation: Assign 'Probable Case' to Case Classification", displayName: "Assign 'Probable Case' to Case Classification", programId: 'PNClHaZARtz', programRuleActions: [{ id: 'NPvy6sF6axT', data: "'Probable Case'", dataElementId: 'Z5z8vFQy0w0', programRuleActionType: 'ASSIGN' }], priority: 4 }, { id: 'E9ghdhg6ABQ', condition: "#{SYMPTOMS} != 'Yes'", description: 'Hide Onset of Symptoms Date if no symptoms', displayName: 'Hide Onset of Symptoms Date', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'VcnnsBPtzlW', dataElementId: 's3eoonJ8OJb', programRuleActionType: 'HIDEFIELD' }] }, { id: 'FnSVDp8v0H9', condition: 'true', description: 'Hide Irrelevant Unknown Options', displayName: 'Hide Unknown Options', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'UqDEcMuF5DF', dataElementId: 'JGnHr6WI3AY', programRuleActionType: 'HIDEOPTION', optionId: 'pqxvAQU1z9W' }, { id: 'GrFjkYTT07o', dataElementId: 'p8htbyJHydl', programRuleActionType: 'HIDEOPTION', optionId: 'pqxvAQU1z9W' }, { id: 'HlyTQaTz00f', dataElementId: 'CUbZcLm9LyN', programRuleActionType: 'HIDEOPTION', optionId: 'pqxvAQU1z9W' }] }, { id: 'L8bP6GifQXL', condition: "!d2:hasValue( #{INFECTION_SOURCE} ) || #{INFECTION_SOURCE} == 'IMPORTED_CASE' || #{INFECTION_SOURCE} == 'EXPOSURE_UNKNOWN'", description: 'Hide Case Type for Imported Cases', displayName: 'Hide Case Type', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'k05Owr8pwIn', dataElementId: 'A4Fg6jgWauf', programRuleActionType: 'HIDEFIELD' }] }, { id: 'MLS5vZLguQM', condition: "#{INFECTION_SOURCE} != 'LOCAL_TRANSMISSION'", description: "Hide 'Specify Local Infection Source' unless Local Transmission is selected", displayName: "Hide 'Specify Local Infection Source'", programId: 'PNClHaZARtz', programRuleActions: [{ id: 'ho7xRPUB0Gl', dataElementId: 'jBBkFuPKctq', programRuleActionType: 'HIDEFIELD' }] }, { id: 'NXWk8sq70OV', condition: "#{TRAVEL_HISTORY} == 'No'", description: "Hide 'Imported Case' if not traveled", displayName: "Hide 'Imported Case'", programId: 'PNClHaZARtz', programRuleActions: [{ id: 'fJIgmDK53Vp', dataElementId: 'f8j4XDEozvj', programRuleActionType: 'HIDEOPTION', optionId: 'PMGTqmVIF4T' }] }, { id: 'NZaVqr7dPfQ', condition: '!d2:hasValue( #{ONSET_DATE} ) && !d2:hasValue(V{event_date})', description: 'Automation: Assign Empty date if no Onset date and no event date is available', displayName: 'Assign Empty Date', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'q060xuOwQx3', data: "''", dataElementId: 'PFXeJV8d7ja', programRuleActionType: 'ASSIGN' }], priority: 3 }, { id: 'QrJx9LI9KRo', condition: "d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'Yes' && !d2:hasValue( #{TEST_RESULT} )", description: 'Automation: Assign Empty Value to Class Classification', displayName: 'Assign Empty Value to Class Classification', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'rFaZAbOgMSz', data: "''", dataElementId: 'Z5z8vFQy0w0', programRuleActionType: 'ASSIGN' }], priority: 2 }, { id: 'R6oEX1xlQma', condition: 'true', description: 'Hide irrelevant Outcome Options', displayName: 'Hide Outcome Options', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'Ov7qHXf0Q2s', dataElementId: 'bOYWVEBaWy6', programRuleActionType: 'HIDEOPTION', optionId: 'dUeRcF2cApV' }, { id: 'V95rgvUlqY0', dataElementId: 'bOYWVEBaWy6', programRuleActionType: 'HIDEOPTION', optionId: 'bYt4why1tL3' }, { id: 'eZUUOjykbLv', dataElementId: 'bOYWVEBaWy6', programRuleActionType: 'HIDEOPTION', optionId: 'xBoo6HyaYcd' }, { id: 'Zcs7rz5VEF7', dataElementId: 'bOYWVEBaWy6', programRuleActionType: 'HIDEOPTION', optionId: 'RCT079wdeKT' }] }, { id: 'dZsTiQEUg5L', condition: '!d2:hasValue( #{ONSET_DATE} ) && d2:hasValue(V{event_date})', description: 'Automation: Assign Event date if no Onset date is available', displayName: 'Assign Event Date', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'sQKFBORp5P1', data: 'V{event_date}', dataElementId: 'PFXeJV8d7ja', programRuleActionType: 'ASSIGN' }], priority: 2 }, { id: 'kVBrxwODyTj', condition: '!d2:hasValue( #{LAB_TEST} )', description: 'Hide Case Classification Field until Lab Test question is answered', displayName: 'Hide Case Classification Field', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'ZT8AexxBPl0', dataElementId: 'Z5z8vFQy0w0', programRuleActionType: 'HIDEFIELD' }] }, { id: 'q2QbEfeDlI9', condition: "!d2:hasValue( #{HOSPITALISED} ) || #{HOSPITALISED} == 'No'", description: 'Hide ICU field unless Hospitalised', displayName: 'Hide ICU field', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'wwvxLCpuOCx', dataElementId: 'p8htbyJHydl', programRuleActionType: 'HIDEFIELD' }] }, { id: 'rZUpiMuJIKH', condition: "d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'Yes' && #{TEST_RESULT} == 'Positive'", description: "Automation: Assign 'Laboratory Confirmed Case' to Case Classification", displayName: "Assign 'Laboratory Confirmed Case' to Case Classification", programId: 'PNClHaZARtz', programRuleActions: [{ id: 'hcamYSDn00P', data: "'Laboratory Confirmed Case'", dataElementId: 'Z5z8vFQy0w0', programRuleActionType: 'ASSIGN' }], priority: 3 }, { id: 'sEQsGGAQSJT', condition: "(d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'Unknown') ||\n(d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'Yes' && (#{TEST_RESULT} == 'Negative' || #{TEST_RESULT} == 'Unknown'))", description: "Automation: Assign Suspected Case' to Case Classification", displayName: "Assign 'Suspected Case' to Case Classification", programId: 'PNClHaZARtz', programRuleActions: [{ id: 'zxb2XDboGAF', data: "'Suspected Case'", dataElementId: 'Z5z8vFQy0w0', programRuleActionType: 'ASSIGN' }], priority: 1 }, { id: 'sKCZMuWwOKA', condition: 'd2:hasValue( #{ONSET_DATE} )', description: 'Automation: Assign Symptoms Onset Date if available', displayName: 'Assign Onset Date', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'lJOYxhjupxz', data: '#{ONSET_DATE}', dataElementId: 'PFXeJV8d7ja', programRuleActionType: 'ASSIGN' }], priority: 1 }, { id: 'vj5GWKIrhKh', condition: "#{LAB_TEST} != 'Yes'", description: 'Hide Test Result Field until Lab Test question is answered with yes', displayName: 'Hide Test Result Field', programId: 'PNClHaZARtz', programRuleActions: [{ id: 'VxxxIX2598r', dataElementId: 'ovY6E8BSdto', programRuleActionType: 'HIDEFIELD' }] }]; - const programRuleVariables = [{ id: 'DoRHHfNPccb', dataElementId: 'f8j4XDEozvj', displayName: 'INFECTION_SOURCE', programId: 'PNClHaZARtz', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', useNameForOptionSet: false }, { id: 'EnpvdmYrwLb', dataElementId: 'TzqawmlPkI5', displayName: 'TRAVEL_HISTORY', programId: 'PNClHaZARtz', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', useNameForOptionSet: true }, { id: 'JPIyrAmJapV', dataElementId: 'CUbZcLm9LyN', displayName: 'HOSPITALISED', programId: 'PNClHaZARtz', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', useNameForOptionSet: true }, { id: 'LAaPMTz69L7', displayName: 'CASE_CLASSIFICATION', programId: 'PNClHaZARtz', programRuleVariableSourceType: 'CALCULATED_VALUE', useNameForOptionSet: true, valueType: 'TEXT' }, { id: 'MpixycZvu0m', dataElementId: 'ovY6E8BSdto', displayName: 'TEST_RESULT', programId: 'PNClHaZARtz', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', useNameForOptionSet: true }, { id: 'XcPYCpTOPwB', dataElementId: 'QQLXTXVidW2', displayName: 'LAB_TEST', programId: 'PNClHaZARtz', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', useNameForOptionSet: true }, { id: 'cZSslcAEupI', dataElementId: 's3eoonJ8OJb', displayName: 'ONSET_DATE', programId: 'PNClHaZARtz', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', useNameForOptionSet: true }, { id: 'eSq3nc1t2F6', dataElementId: 'dyfYIsTFTjG', displayName: 'PATIENT_ID', programId: 'PNClHaZARtz', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', useNameForOptionSet: true }, { id: 'lY0yJGU1D4e', dataElementId: 'JGnHr6WI3AY', displayName: 'SYMPTOMS', programId: 'PNClHaZARtz', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', useNameForOptionSet: false }]; + const constants = [ + { id: 'Gfd3ppDfq8E', displayName: 'Commodity ordering overhead', value: 5 }, + { id: 'bCqvfPR02Im', displayName: 'Pi', value: 3.14 }, + ]; + const dataElementsInProgram = { + dyfYIsTFTjG: { id: 'dyfYIsTFTjG', valueType: 'TEXT' }, + XOaXLWuhKzV: { id: 'XOaXLWuhKzV', valueType: 'TEXT', optionSetId: 'WDUwjiW2rGH' }, + AtFlciXnstG: { id: 'AtFlciXnstG', valueType: 'INTEGER_ZERO_OR_POSITIVE' }, + JGnHr6WI3AY: { id: 'JGnHr6WI3AY', valueType: 'TEXT', optionSetId: 'L6eMZDJkCwX' }, + s3eoonJ8OJb: { id: 's3eoonJ8OJb', valueType: 'DATE' }, + gktroFPckdr: { id: 'gktroFPckdr', valueType: 'TEXT', optionSetId: 'UYDsNdpo2BU' }, + QQLXTXVidW2: { id: 'QQLXTXVidW2', valueType: 'TEXT', optionSetId: 'L6eMZDJkCwX' }, + ovY6E8BSdto: { id: 'ovY6E8BSdto', valueType: 'TEXT', optionSetId: 'dsgBmIZ0Yrq' }, + Z5z8vFQy0w0: { id: 'Z5z8vFQy0w0', valueType: 'TEXT' }, + TzqawmlPkI5: { id: 'TzqawmlPkI5', valueType: 'TEXT', optionSetId: 'L6eMZDJkCwX' }, + f8j4XDEozvj: { id: 'f8j4XDEozvj', valueType: 'TEXT', optionSetId: 'xD9QOIvNAjw' }, + jBBkFuPKctq: { id: 'jBBkFuPKctq', valueType: 'TEXT', optionSetId: 'T9zjyaIkRqH' }, + A4Fg6jgWauf: { id: 'A4Fg6jgWauf', valueType: 'TEXT', optionSetId: 'w1vUkxq8IOl' }, + CUbZcLm9LyN: { id: 'CUbZcLm9LyN', valueType: 'TEXT', optionSetId: 'L6eMZDJkCwX' }, + p8htbyJHydl: { id: 'p8htbyJHydl', valueType: 'TEXT', optionSetId: 'L6eMZDJkCwX' }, + SbXES4EPgqP: { id: 'SbXES4EPgqP', valueType: 'NUMBER' }, + bOYWVEBaWy6: { id: 'bOYWVEBaWy6', valueType: 'TEXT', optionSetId: 'qI4cs9ocBwn' }, + PFXeJV8d7ja: { id: 'PFXeJV8d7ja', valueType: 'DATE' }, + }; + const programRules = [ + { + id: 'DOz4wl8ErDD', + condition: 'true', + description: 'Hide Irrelevant Test Result Options', + displayName: 'Hide Test Result Options', + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'XuM1JizlcF1', + dataElementId: 'ovY6E8BSdto', + programRuleActionType: 'HIDEOPTION', + optionId: 'MkeWrqeqZXL', + }, + { + id: 'FRfTFXSwKDU', + dataElementId: 'ovY6E8BSdto', + programRuleActionType: 'HIDEOPTION', + optionId: 'fPV0gQ8ds6D', + }, + ], + }, + { + id: 'DtfaG1TgyZk', + condition: + "(d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'No') ||\n(d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'Yes' && #{TEST_RESULT} == 'Inconclusive')", + description: "Automation: Assign 'Probable Case' to Case Classification", + displayName: "Assign 'Probable Case' to Case Classification", + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'NPvy6sF6axT', + data: "'Probable Case'", + dataElementId: 'Z5z8vFQy0w0', + programRuleActionType: 'ASSIGN', + }, + ], + priority: 4, + }, + { + id: 'E9ghdhg6ABQ', + condition: "#{SYMPTOMS} != 'Yes'", + description: 'Hide Onset of Symptoms Date if no symptoms', + displayName: 'Hide Onset of Symptoms Date', + programId: 'PNClHaZARtz', + programRuleActions: [ + { id: 'VcnnsBPtzlW', dataElementId: 's3eoonJ8OJb', programRuleActionType: 'HIDEFIELD' }, + ], + }, + { + id: 'FnSVDp8v0H9', + condition: 'true', + description: 'Hide Irrelevant Unknown Options', + displayName: 'Hide Unknown Options', + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'UqDEcMuF5DF', + dataElementId: 'JGnHr6WI3AY', + programRuleActionType: 'HIDEOPTION', + optionId: 'pqxvAQU1z9W', + }, + { + id: 'GrFjkYTT07o', + dataElementId: 'p8htbyJHydl', + programRuleActionType: 'HIDEOPTION', + optionId: 'pqxvAQU1z9W', + }, + { + id: 'HlyTQaTz00f', + dataElementId: 'CUbZcLm9LyN', + programRuleActionType: 'HIDEOPTION', + optionId: 'pqxvAQU1z9W', + }, + ], + }, + { + id: 'L8bP6GifQXL', + condition: + "!d2:hasValue( #{INFECTION_SOURCE} ) || #{INFECTION_SOURCE} == 'IMPORTED_CASE' || #{INFECTION_SOURCE} == 'EXPOSURE_UNKNOWN'", + description: 'Hide Case Type for Imported Cases', + displayName: 'Hide Case Type', + programId: 'PNClHaZARtz', + programRuleActions: [ + { id: 'k05Owr8pwIn', dataElementId: 'A4Fg6jgWauf', programRuleActionType: 'HIDEFIELD' }, + ], + }, + { + id: 'MLS5vZLguQM', + condition: "#{INFECTION_SOURCE} != 'LOCAL_TRANSMISSION'", + description: "Hide 'Specify Local Infection Source' unless Local Transmission is selected", + displayName: "Hide 'Specify Local Infection Source'", + programId: 'PNClHaZARtz', + programRuleActions: [ + { id: 'ho7xRPUB0Gl', dataElementId: 'jBBkFuPKctq', programRuleActionType: 'HIDEFIELD' }, + ], + }, + { + id: 'NXWk8sq70OV', + condition: "#{TRAVEL_HISTORY} == 'No'", + description: "Hide 'Imported Case' if not traveled", + displayName: "Hide 'Imported Case'", + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'fJIgmDK53Vp', + dataElementId: 'f8j4XDEozvj', + programRuleActionType: 'HIDEOPTION', + optionId: 'PMGTqmVIF4T', + }, + ], + }, + { + id: 'NZaVqr7dPfQ', + condition: '!d2:hasValue( #{ONSET_DATE} ) && !d2:hasValue(V{event_date})', + description: 'Automation: Assign Empty date if no Onset date and no event date is available', + displayName: 'Assign Empty Date', + programId: 'PNClHaZARtz', + programRuleActions: [ + { id: 'q060xuOwQx3', data: "''", dataElementId: 'PFXeJV8d7ja', programRuleActionType: 'ASSIGN' }, + ], + priority: 3, + }, + { + id: 'QrJx9LI9KRo', + condition: "d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'Yes' && !d2:hasValue( #{TEST_RESULT} )", + description: 'Automation: Assign Empty Value to Class Classification', + displayName: 'Assign Empty Value to Class Classification', + programId: 'PNClHaZARtz', + programRuleActions: [ + { id: 'rFaZAbOgMSz', data: "''", dataElementId: 'Z5z8vFQy0w0', programRuleActionType: 'ASSIGN' }, + ], + priority: 2, + }, + { + id: 'R6oEX1xlQma', + condition: 'true', + description: 'Hide irrelevant Outcome Options', + displayName: 'Hide Outcome Options', + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'Ov7qHXf0Q2s', + dataElementId: 'bOYWVEBaWy6', + programRuleActionType: 'HIDEOPTION', + optionId: 'dUeRcF2cApV', + }, + { + id: 'V95rgvUlqY0', + dataElementId: 'bOYWVEBaWy6', + programRuleActionType: 'HIDEOPTION', + optionId: 'bYt4why1tL3', + }, + { + id: 'eZUUOjykbLv', + dataElementId: 'bOYWVEBaWy6', + programRuleActionType: 'HIDEOPTION', + optionId: 'xBoo6HyaYcd', + }, + { + id: 'Zcs7rz5VEF7', + dataElementId: 'bOYWVEBaWy6', + programRuleActionType: 'HIDEOPTION', + optionId: 'RCT079wdeKT', + }, + ], + }, + { + id: 'dZsTiQEUg5L', + condition: '!d2:hasValue( #{ONSET_DATE} ) && d2:hasValue(V{event_date})', + description: 'Automation: Assign Event date if no Onset date is available', + displayName: 'Assign Event Date', + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'sQKFBORp5P1', + data: 'V{event_date}', + dataElementId: 'PFXeJV8d7ja', + programRuleActionType: 'ASSIGN', + }, + ], + priority: 2, + }, + { + id: 'kVBrxwODyTj', + condition: '!d2:hasValue( #{LAB_TEST} )', + description: 'Hide Case Classification Field until Lab Test question is answered', + displayName: 'Hide Case Classification Field', + programId: 'PNClHaZARtz', + programRuleActions: [ + { id: 'ZT8AexxBPl0', dataElementId: 'Z5z8vFQy0w0', programRuleActionType: 'HIDEFIELD' }, + ], + }, + { + id: 'q2QbEfeDlI9', + condition: "!d2:hasValue( #{HOSPITALISED} ) || #{HOSPITALISED} == 'No'", + description: 'Hide ICU field unless Hospitalised', + displayName: 'Hide ICU field', + programId: 'PNClHaZARtz', + programRuleActions: [ + { id: 'wwvxLCpuOCx', dataElementId: 'p8htbyJHydl', programRuleActionType: 'HIDEFIELD' }, + ], + }, + { + id: 'rZUpiMuJIKH', + condition: "d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'Yes' && #{TEST_RESULT} == 'Positive'", + description: "Automation: Assign 'Laboratory Confirmed Case' to Case Classification", + displayName: "Assign 'Laboratory Confirmed Case' to Case Classification", + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'hcamYSDn00P', + data: "'Laboratory Confirmed Case'", + dataElementId: 'Z5z8vFQy0w0', + programRuleActionType: 'ASSIGN', + }, + ], + priority: 3, + }, + { + id: 'sEQsGGAQSJT', + condition: + "(d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'Unknown') ||\n(d2:hasValue( #{LAB_TEST} ) && #{LAB_TEST} == 'Yes' && (#{TEST_RESULT} == 'Negative' || #{TEST_RESULT} == 'Unknown'))", + description: "Automation: Assign Suspected Case' to Case Classification", + displayName: "Assign 'Suspected Case' to Case Classification", + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'zxb2XDboGAF', + data: "'Suspected Case'", + dataElementId: 'Z5z8vFQy0w0', + programRuleActionType: 'ASSIGN', + }, + ], + priority: 1, + }, + { + id: 'sKCZMuWwOKA', + condition: 'd2:hasValue( #{ONSET_DATE} )', + description: 'Automation: Assign Symptoms Onset Date if available', + displayName: 'Assign Onset Date', + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'lJOYxhjupxz', + data: '#{ONSET_DATE}', + dataElementId: 'PFXeJV8d7ja', + programRuleActionType: 'ASSIGN', + }, + ], + priority: 1, + }, + { + id: 'vj5GWKIrhKh', + condition: "#{LAB_TEST} != 'Yes'", + description: 'Hide Test Result Field until Lab Test question is answered with yes', + displayName: 'Hide Test Result Field', + programId: 'PNClHaZARtz', + programRuleActions: [ + { id: 'VxxxIX2598r', dataElementId: 'ovY6E8BSdto', programRuleActionType: 'HIDEFIELD' }, + ], + }, + ]; + const programRuleVariables = [ + { + id: 'DoRHHfNPccb', + dataElementId: 'f8j4XDEozvj', + displayName: 'INFECTION_SOURCE', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: false, + }, + { + id: 'EnpvdmYrwLb', + dataElementId: 'TzqawmlPkI5', + displayName: 'TRAVEL_HISTORY', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: true, + }, + { + id: 'JPIyrAmJapV', + dataElementId: 'CUbZcLm9LyN', + displayName: 'HOSPITALISED', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: true, + }, + { + id: 'LAaPMTz69L7', + displayName: 'CASE_CLASSIFICATION', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.CALCULATED_VALUE, + useNameForOptionSet: true, + valueType: 'TEXT', + }, + { + id: 'MpixycZvu0m', + dataElementId: 'ovY6E8BSdto', + displayName: 'TEST_RESULT', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: true, + }, + { + id: 'XcPYCpTOPwB', + dataElementId: 'QQLXTXVidW2', + displayName: 'LAB_TEST', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: true, + }, + { + id: 'cZSslcAEupI', + dataElementId: 's3eoonJ8OJb', + displayName: 'ONSET_DATE', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: true, + }, + { + id: 'eSq3nc1t2F6', + dataElementId: 'dyfYIsTFTjG', + displayName: 'PATIENT_ID', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: true, + }, + { + id: 'lY0yJGU1D4e', + dataElementId: 'JGnHr6WI3AY', + displayName: 'SYMPTOMS', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: false, + }, + ]; const orgUnit = { id: 'DiszpKrYNg8', name: 'Ngelehun CHC' }; const optionSets = { - L6eMZDJkCwX: { id: 'L6eMZDJkCwX', displayName: 'Yes/No/Unknown', version: 3, valueType: 'TEXT', options: [{ id: 'x9yVKkv9koc', displayName: 'Yes', code: 'Yes', translations: [{ property: 'NAME', locale: 'uz@Latn', value: 'Ha' }, { property: 'NAME', locale: 'fr', value: 'Oui' }, { property: 'NAME', locale: 'pt', value: 'Sim' }, { property: 'NAME', locale: 'uz@Cyrl', value: 'Ҳа' }, { property: 'NAME', locale: 'es', value: 'Sí' }, { property: 'NAME', locale: 'nb', value: 'Ja' }, { property: 'NAME', locale: 'ru', value: 'да' }] }, { id: 'R98tI2c6rF5', displayName: 'No', code: 'No', translations: [{ property: 'NAME', locale: 'nb', value: 'Nei' }, { property: 'NAME', locale: 'es', value: 'No' }, { property: 'NAME', locale: 'uz@Latn', value: 'Yo`q' }, { property: 'NAME', locale: 'ru', value: 'нет' }, { property: 'NAME', locale: 'pt', value: 'Não' }, { property: 'NAME', locale: 'fr', value: 'Non' }, { property: 'NAME', locale: 'uz@Cyrl', value: 'Йўқ' }] }, { id: 'pqxvAQU1z9W', displayName: 'Unknown', code: 'Unknown', translations: [{ property: 'NAME', locale: 'es', value: 'DEsconocido' }, { property: 'NAME', locale: 'nb', value: 'Ukjent' }, { property: 'NAME', locale: 'uz@Cyrl', value: 'Ноаниқ' }, { property: 'NAME', locale: 'fr', value: 'Inconnu' }, { property: 'NAME', locale: 'uz@Latn', value: 'Noaniq' }, { property: 'NAME', locale: 'pt', value: 'Desconhecido' }, { property: 'NAME', locale: 'ru', value: 'Неизвестно' }] }] }, - dsgBmIZ0Yrq: { id: 'dsgBmIZ0Yrq', displayName: 'Test Result', version: 6, valueType: 'TEXT', options: [{ id: 'B44lkxTWbGO', displayName: 'Inconclusive', code: 'Inconclusive', translations: [{ property: 'NAME', locale: 'fr', value: 'Non concluant' }, { property: 'NAME', locale: 'pt', value: 'Inconclusivo' }, { property: 'NAME', locale: 'nb', value: 'Mangelfull' }, { property: 'NAME', locale: 'es', value: 'No concluyente' }, { property: 'NAME', locale: 'ru', value: 'Неокончательный' }] }, { id: 'ljClr1z2aE7', displayName: 'Negative', code: 'Negative', translations: [{ property: 'NAME', locale: 'fr', value: 'Négatif' }, { property: 'NAME', locale: 'nb', value: 'Negativ' }, { property: 'NAME', locale: 'es', value: 'Negativo' }, { property: 'NAME', locale: 'uz@Latn', value: 'Manfiy' }, { property: 'NAME', locale: 'pt', value: 'Negativo' }, { property: 'NAME', locale: 'ru', value: 'Отрицательный' }, { property: 'NAME', locale: 'uz@Cyrl', value: 'Манфий' }] }, { id: 'LKbwTJwocOk', displayName: 'Positive', code: 'Positive', translations: [{ property: 'NAME', locale: 'ru', value: 'Положительный' }, { property: 'NAME', locale: 'es', value: 'Positivo' }, { property: 'NAME', locale: 'uz@Latn', value: 'Musbat' }, { property: 'NAME', locale: 'uz@Cyrl', value: 'Мусбат' }, { property: 'NAME', locale: 'nb', value: 'Positiv' }, { property: 'NAME', locale: 'fr', value: 'Positif' }, { property: 'NAME', locale: 'pt', value: 'Positivo' }] }, { id: 'MkeWrqeqZXL', displayName: 'Not performed', code: 'Not performed', translations: [{ property: 'NAME', locale: 'ru', value: 'Не выполнен' }, { property: 'NAME', locale: 'pt', value: 'Não realizado' }, { property: 'NAME', locale: 'nb', value: 'Ikke utført' }, { property: 'NAME', locale: 'fr', value: 'Non réalisé' }, { property: 'NAME', locale: 'es', value: 'No realizado' }] }, { id: 'fPV0gQ8ds6D', displayName: 'Invalid', code: 'Invalid', translations: [{ property: 'NAME', locale: 'es', value: 'Inválido' }, { property: 'NAME', locale: 'fr', value: 'Invalide' }, { property: 'NAME', locale: 'pt', value: 'Inválido' }, { property: 'NAME', locale: 'nb', value: 'Ugyldig' }, { property: 'NAME', locale: 'ru', value: 'Недействительный' }] }, { id: 'YV3jCZlvwZe', displayName: 'Unknown', code: 'Unknown', translations: [{ property: 'NAME', locale: 'es', value: 'DEsconocido' }, { property: 'NAME', locale: 'nb', value: 'Ukjent' }, { property: 'NAME', locale: 'uz@Cyrl', value: 'Ноаниқ' }, { property: 'NAME', locale: 'fr', value: 'Inconnu' }, { property: 'NAME', locale: 'uz@Latn', value: 'Noaniq' }, { property: 'NAME', locale: 'pt', value: 'Desconhecido' }, { property: 'NAME', locale: 'ru', value: 'Неизвестно' }] }] }, + L6eMZDJkCwX: { + id: 'L6eMZDJkCwX', + displayName: 'Yes/No/Unknown', + version: 3, + valueType: 'TEXT', + options: [ + { + id: 'x9yVKkv9koc', + displayName: 'Yes', + code: 'Yes', + translations: [ + { property: 'NAME', locale: 'uz@Latn', value: 'Ha' }, + { property: 'NAME', locale: 'fr', value: 'Oui' }, + { property: 'NAME', locale: 'pt', value: 'Sim' }, + { property: 'NAME', locale: 'uz@Cyrl', value: 'Ҳа' }, + { property: 'NAME', locale: 'es', value: 'Sí' }, + { property: 'NAME', locale: 'nb', value: 'Ja' }, + { property: 'NAME', locale: 'ru', value: 'да' }, + ], + }, + { + id: 'R98tI2c6rF5', + displayName: 'No', + code: 'No', + translations: [ + { property: 'NAME', locale: 'nb', value: 'Nei' }, + { property: 'NAME', locale: 'es', value: 'No' }, + { property: 'NAME', locale: 'uz@Latn', value: 'Yo`q' }, + { property: 'NAME', locale: 'ru', value: 'нет' }, + { property: 'NAME', locale: 'pt', value: 'Não' }, + { property: 'NAME', locale: 'fr', value: 'Non' }, + { property: 'NAME', locale: 'uz@Cyrl', value: 'Йўқ' }, + ], + }, + { + id: 'pqxvAQU1z9W', + code: 'Unknown', + translations: [ + { property: 'NAME', locale: 'es', value: 'DEsconocido' }, + { property: 'NAME', locale: 'nb', value: 'Ukjent' }, + { property: 'NAME', locale: 'uz@Cyrl', value: 'Ноаниқ' }, + { property: 'NAME', locale: 'fr', value: 'Inconnu' }, + { property: 'NAME', locale: 'uz@Latn', value: 'Noaniq' }, + { property: 'NAME', locale: 'pt', value: 'Desconhecido' }, + { property: 'NAME', locale: 'ru', value: 'Неизвестно' }, + ], + }, + ], + }, + dsgBmIZ0Yrq: { + id: 'dsgBmIZ0Yrq', + displayName: 'Test Result', + version: 6, + valueType: 'TEXT', + options: [ + { + id: 'B44lkxTWbGO', + code: 'Inconclusive', + translations: [ + { property: 'NAME', locale: 'fr', value: 'Non concluant' }, + { property: 'NAME', locale: 'pt', value: 'Inconclusivo' }, + { property: 'NAME', locale: 'nb', value: 'Mangelfull' }, + { property: 'NAME', locale: 'es', value: 'No concluyente' }, + { property: 'NAME', locale: 'ru', value: 'Неокончательный' }, + ], + }, + { + id: 'ljClr1z2aE7', + displayName: 'Negative', + code: 'Negative', + translations: [ + { property: 'NAME', locale: 'fr', value: 'Négatif' }, + { property: 'NAME', locale: 'nb', value: 'Negativ' }, + { property: 'NAME', locale: 'es', value: 'Negativo' }, + { property: 'NAME', locale: 'uz@Latn', value: 'Manfiy' }, + { property: 'NAME', locale: 'pt', value: 'Negativo' }, + { property: 'NAME', locale: 'ru', value: 'Отрицательный' }, + { property: 'NAME', locale: 'uz@Cyrl', value: 'Манфий' }, + ], + }, + { + id: 'LKbwTJwocOk', + displayName: 'Positive', + code: 'Positive', + translations: [ + { property: 'NAME', locale: 'ru', value: 'Положительный' }, + { property: 'NAME', locale: 'es', value: 'Positivo' }, + { property: 'NAME', locale: 'uz@Latn', value: 'Musbat' }, + { property: 'NAME', locale: 'uz@Cyrl', value: 'Мусбат' }, + { property: 'NAME', locale: 'nb', value: 'Positiv' }, + { property: 'NAME', locale: 'fr', value: 'Positif' }, + { property: 'NAME', locale: 'pt', value: 'Positivo' }, + ], + }, + { + id: 'MkeWrqeqZXL', + displayName: 'Not performed', + code: 'Not performed', + translations: [ + { property: 'NAME', locale: 'ru', value: 'Не выполнен' }, + { property: 'NAME', locale: 'pt', value: 'Não realizado' }, + { property: 'NAME', locale: 'nb', value: 'Ikke utført' }, + { property: 'NAME', locale: 'fr', value: 'Non réalisé' }, + { property: 'NAME', locale: 'es', value: 'No realizado' }, + ], + }, + { + id: 'fPV0gQ8ds6D', + displayName: 'Invalid', + code: 'Invalid', + translations: [ + { property: 'NAME', locale: 'es', value: 'Inválido' }, + { property: 'NAME', locale: 'fr', value: 'Invalide' }, + { property: 'NAME', locale: 'pt', value: 'Inválido' }, + { property: 'NAME', locale: 'nb', value: 'Ugyldig' }, + { property: 'NAME', locale: 'ru', value: 'Недействительный' }, + ], + }, + { + id: 'YV3jCZlvwZe', + displayName: 'Unknown', + code: 'Unknown', + translations: [ + { property: 'NAME', locale: 'es', value: 'DEsconocido' }, + { property: 'NAME', locale: 'nb', value: 'Ukjent' }, + { property: 'NAME', locale: 'uz@Cyrl', value: 'Ноаниқ' }, + { property: 'NAME', locale: 'fr', value: 'Inconnu' }, + { property: 'NAME', locale: 'uz@Latn', value: 'Noaniq' }, + { property: 'NAME', locale: 'pt', value: 'Desconhecido' }, + { property: 'NAME', locale: 'ru', value: 'Неизвестно' }, + ], + }, + ], + }, }; // NOTE: in this test we dont use toMatchSnapshot instead we test again hardcoded values. Since the effects are plenty @@ -167,18 +916,68 @@ describe('Event rules engine', () => { [ { JGnHr6WI3AY: 'Yes' }, [ - { type: 'ASSIGN', id: 'PFXeJV8d7ja', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'MkeWrqeqZXL' }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'fPV0gQ8ds6D' }, - { type: 'HIDEOPTION', id: 'JGnHr6WI3AY', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'CUbZcLm9LyN', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, + { + type: 'ASSIGN', + id: 'PFXeJV8d7ja', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'MkeWrqeqZXL', + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'fPV0gQ8ds6D', + }, + { + type: 'HIDEOPTION', + id: 'JGnHr6WI3AY', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'p8htbyJHydl', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'CUbZcLm9LyN', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, { type: 'HIDEFIELD', id: 'A4Fg6jgWauf', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'jBBkFuPKctq', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'dUeRcF2cApV' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'bYt4why1tL3' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'xBoo6HyaYcd' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'RCT079wdeKT' }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'dUeRcF2cApV', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'bYt4why1tL3', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'xBoo6HyaYcd', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'RCT079wdeKT', + }, { type: 'HIDEFIELD', id: 'Z5z8vFQy0w0', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, @@ -187,40 +986,150 @@ describe('Event rules engine', () => { [ { QQLXTXVidW2: 'Yes' }, [ - { type: 'ASSIGN', id: 'Z5z8vFQy0w0', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'ASSIGN', id: 'PFXeJV8d7ja', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'MkeWrqeqZXL' }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'fPV0gQ8ds6D' }, + { + type: 'ASSIGN', + id: 'Z5z8vFQy0w0', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'ASSIGN', + id: 'PFXeJV8d7ja', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'MkeWrqeqZXL', + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'fPV0gQ8ds6D', + }, { type: 'HIDEFIELD', id: 's3eoonJ8OJb', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'JGnHr6WI3AY', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'CUbZcLm9LyN', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, + { + type: 'HIDEOPTION', + id: 'JGnHr6WI3AY', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'p8htbyJHydl', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'CUbZcLm9LyN', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, { type: 'HIDEFIELD', id: 'A4Fg6jgWauf', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'jBBkFuPKctq', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'dUeRcF2cApV' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'bYt4why1tL3' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'xBoo6HyaYcd' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'RCT079wdeKT' }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'dUeRcF2cApV', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'bYt4why1tL3', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'xBoo6HyaYcd', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'RCT079wdeKT', + }, { type: 'HIDEFIELD', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, ], ], [ { QQLXTXVidW2: 'No' }, [ - { type: 'ASSIGN', id: 'PFXeJV8d7ja', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'ASSIGN', id: 'Z5z8vFQy0w0', value: 'Probable Case', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'MkeWrqeqZXL' }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'fPV0gQ8ds6D' }, + { + type: 'ASSIGN', + id: 'PFXeJV8d7ja', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'ASSIGN', + id: 'Z5z8vFQy0w0', + value: 'Probable Case', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'MkeWrqeqZXL', + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'fPV0gQ8ds6D', + }, { type: 'HIDEFIELD', id: 's3eoonJ8OJb', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'JGnHr6WI3AY', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'CUbZcLm9LyN', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, + { + type: 'HIDEOPTION', + id: 'JGnHr6WI3AY', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'p8htbyJHydl', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'CUbZcLm9LyN', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, { type: 'HIDEFIELD', id: 'A4Fg6jgWauf', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'jBBkFuPKctq', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'dUeRcF2cApV' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'bYt4why1tL3' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'xBoo6HyaYcd' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'RCT079wdeKT' }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'dUeRcF2cApV', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'bYt4why1tL3', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'xBoo6HyaYcd', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'RCT079wdeKT', + }, { type: 'HIDEFIELD', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, ], @@ -228,20 +1137,75 @@ describe('Event rules engine', () => { [ { QQLXTXVidW2: 'Unknown' }, [ - { type: 'ASSIGN', id: 'Z5z8vFQy0w0', value: 'Suspected Case', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'ASSIGN', id: 'PFXeJV8d7ja', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'MkeWrqeqZXL' }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'fPV0gQ8ds6D' }, + { + type: 'ASSIGN', + id: 'Z5z8vFQy0w0', + value: 'Suspected Case', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'ASSIGN', + id: 'PFXeJV8d7ja', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'MkeWrqeqZXL', + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'fPV0gQ8ds6D', + }, { type: 'HIDEFIELD', id: 's3eoonJ8OJb', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'JGnHr6WI3AY', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'CUbZcLm9LyN', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, + { + type: 'HIDEOPTION', + id: 'JGnHr6WI3AY', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'p8htbyJHydl', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'CUbZcLm9LyN', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, { type: 'HIDEFIELD', id: 'A4Fg6jgWauf', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'jBBkFuPKctq', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'dUeRcF2cApV' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'bYt4why1tL3' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'xBoo6HyaYcd' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'RCT079wdeKT' }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'dUeRcF2cApV', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'bYt4why1tL3', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'xBoo6HyaYcd', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'RCT079wdeKT', + }, { type: 'HIDEFIELD', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, ], @@ -249,19 +1213,69 @@ describe('Event rules engine', () => { [ { CUbZcLm9LyN: 'Yes' }, [ - { type: 'ASSIGN', id: 'PFXeJV8d7ja', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'MkeWrqeqZXL' }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'fPV0gQ8ds6D' }, + { + type: 'ASSIGN', + id: 'PFXeJV8d7ja', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'MkeWrqeqZXL', + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'fPV0gQ8ds6D', + }, { type: 'HIDEFIELD', id: 's3eoonJ8OJb', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'JGnHr6WI3AY', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'CUbZcLm9LyN', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, + { + type: 'HIDEOPTION', + id: 'JGnHr6WI3AY', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'p8htbyJHydl', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'CUbZcLm9LyN', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, { type: 'HIDEFIELD', id: 'A4Fg6jgWauf', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'jBBkFuPKctq', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'dUeRcF2cApV' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'bYt4why1tL3' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'xBoo6HyaYcd' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'RCT079wdeKT' }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'dUeRcF2cApV', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'bYt4why1tL3', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'xBoo6HyaYcd', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'RCT079wdeKT', + }, { type: 'HIDEFIELD', id: 'Z5z8vFQy0w0', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, ], @@ -269,80 +1283,300 @@ describe('Event rules engine', () => { [ { QQLXTXVidW2: 'Yes', ovY6E8BSdto: 'Inconclusive' }, [ - { type: 'ASSIGN', id: 'PFXeJV8d7ja', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'ASSIGN', id: 'Z5z8vFQy0w0', value: 'Probable Case', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'MkeWrqeqZXL' }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'fPV0gQ8ds6D' }, + { + type: 'ASSIGN', + id: 'PFXeJV8d7ja', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'ASSIGN', + id: 'Z5z8vFQy0w0', + value: 'Probable Case', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'MkeWrqeqZXL', + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'fPV0gQ8ds6D', + }, { type: 'HIDEFIELD', id: 's3eoonJ8OJb', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'JGnHr6WI3AY', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'CUbZcLm9LyN', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, + { + type: 'HIDEOPTION', + id: 'JGnHr6WI3AY', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'p8htbyJHydl', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'CUbZcLm9LyN', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, { type: 'HIDEFIELD', id: 'A4Fg6jgWauf', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'jBBkFuPKctq', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'dUeRcF2cApV' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'bYt4why1tL3' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'xBoo6HyaYcd' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'RCT079wdeKT' }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'dUeRcF2cApV', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'bYt4why1tL3', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'xBoo6HyaYcd', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'RCT079wdeKT', + }, { type: 'HIDEFIELD', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, ], ], [ { QQLXTXVidW2: 'Yes', ovY6E8BSdto: 'Positive' }, [ - { type: 'ASSIGN', id: 'PFXeJV8d7ja', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'ASSIGN', id: 'Z5z8vFQy0w0', value: 'Laboratory Confirmed Case', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'MkeWrqeqZXL' }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'fPV0gQ8ds6D' }, + { + type: 'ASSIGN', + id: 'PFXeJV8d7ja', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'ASSIGN', + id: 'Z5z8vFQy0w0', + value: 'Laboratory Confirmed Case', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'MkeWrqeqZXL', + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'fPV0gQ8ds6D', + }, { type: 'HIDEFIELD', id: 's3eoonJ8OJb', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'JGnHr6WI3AY', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'CUbZcLm9LyN', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, + { + type: 'HIDEOPTION', + id: 'JGnHr6WI3AY', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'p8htbyJHydl', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'CUbZcLm9LyN', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, { type: 'HIDEFIELD', id: 'A4Fg6jgWauf', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'jBBkFuPKctq', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'dUeRcF2cApV' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'bYt4why1tL3' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'xBoo6HyaYcd' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'RCT079wdeKT' }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'dUeRcF2cApV', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'bYt4why1tL3', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'xBoo6HyaYcd', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'RCT079wdeKT', + }, { type: 'HIDEFIELD', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, ], ], [ { QQLXTXVidW2: 'Yes', ovY6E8BSdto: 'Negative' }, [ - { type: 'ASSIGN', id: 'Z5z8vFQy0w0', value: 'Suspected Case', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'ASSIGN', id: 'PFXeJV8d7ja', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'MkeWrqeqZXL' }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'fPV0gQ8ds6D' }, + { + type: 'ASSIGN', + id: 'Z5z8vFQy0w0', + value: 'Suspected Case', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'ASSIGN', + id: 'PFXeJV8d7ja', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'MkeWrqeqZXL', + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'fPV0gQ8ds6D', + }, { type: 'HIDEFIELD', id: 's3eoonJ8OJb', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'JGnHr6WI3AY', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'CUbZcLm9LyN', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, + { + type: 'HIDEOPTION', + id: 'JGnHr6WI3AY', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'p8htbyJHydl', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'CUbZcLm9LyN', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, { type: 'HIDEFIELD', id: 'A4Fg6jgWauf', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'jBBkFuPKctq', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'dUeRcF2cApV' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'bYt4why1tL3' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'xBoo6HyaYcd' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'RCT079wdeKT' }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'dUeRcF2cApV', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'bYt4why1tL3', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'xBoo6HyaYcd', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'RCT079wdeKT', + }, { type: 'HIDEFIELD', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, ], ], [ { QQLXTXVidW2: 'Yes', ovY6E8BSdto: 'Unknown' }, [ - { type: 'ASSIGN', id: 'Z5z8vFQy0w0', value: 'Suspected Case', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'ASSIGN', id: 'PFXeJV8d7ja', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'MkeWrqeqZXL' }, - { type: 'HIDEOPTION', id: 'ovY6E8BSdto', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'fPV0gQ8ds6D' }, + { + type: 'ASSIGN', + id: 'Z5z8vFQy0w0', + value: 'Suspected Case', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'ASSIGN', + id: 'PFXeJV8d7ja', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'MkeWrqeqZXL', + }, + { + type: 'HIDEOPTION', + id: 'ovY6E8BSdto', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'fPV0gQ8ds6D', + }, { type: 'HIDEFIELD', id: 's3eoonJ8OJb', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'JGnHr6WI3AY', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, - { type: 'HIDEOPTION', id: 'CUbZcLm9LyN', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'pqxvAQU1z9W' }, + { + type: 'HIDEOPTION', + id: 'JGnHr6WI3AY', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'p8htbyJHydl', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, + { + type: 'HIDEOPTION', + id: 'CUbZcLm9LyN', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'pqxvAQU1z9W', + }, { type: 'HIDEFIELD', id: 'A4Fg6jgWauf', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, { type: 'HIDEFIELD', id: 'jBBkFuPKctq', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'dUeRcF2cApV' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'bYt4why1tL3' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'xBoo6HyaYcd' }, - { type: 'HIDEOPTION', id: 'bOYWVEBaWy6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, optionId: 'RCT079wdeKT' }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'dUeRcF2cApV', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'bYt4why1tL3', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'xBoo6HyaYcd', + }, + { + type: 'HIDEOPTION', + id: 'bOYWVEBaWy6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + optionId: 'RCT079wdeKT', + }, { type: 'HIDEFIELD', id: 'p8htbyJHydl', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, ], ], @@ -361,15 +1595,261 @@ describe('Event rules engine', () => { }); }); - describe('Event rules engine effects with functions and effects', () => { // these variables are shared between each test - const constants = [{ id: 'Gfd3ppDfq8E', displayName: 'Commodity ordering overhead', value: 5 }, { id: 'bCqvfPR02Im', displayName: 'Pi', value: 3.14 }]; - const dataElementsInProgram = { oZg33kd9taw: { id: 'oZg33kd9taw', valueType: 'TEXT', optionSetId: 'pC3N9N77UmT' }, SWfdB5lX0fk: { id: 'SWfdB5lX0fk', valueType: 'BOOLEAN' }, qrur9Dvnyt5: { id: 'qrur9Dvnyt5', valueType: 'INTEGER' }, GieVkTxp4HH: { id: 'GieVkTxp4HH', valueType: 'NUMBER' }, vV9UWAZohSf: { id: 'vV9UWAZohSf', valueType: 'INTEGER_POSITIVE' }, eMyVanycQSC: { id: 'eMyVanycQSC', valueType: 'DATE' }, K6uUAvq500H: { id: 'K6uUAvq500H', valueType: 'TEXT', optionSetId: 'eUZ79clX7y1' }, msodh3rEMJa: { id: 'msodh3rEMJa', valueType: 'DATE' }, S33cRBsnXPo: { id: 'S33cRBsnXPo', valueType: 'ORGANISATION_UNIT' }, fWIAEtYVEGk: { id: 'fWIAEtYVEGk', valueType: 'TEXT', optionSetId: 'iDFPKpFTiVw' }, ulD2zW0TIy2: { id: 'ulD2zW0TIy2', valueType: 'FILE_RESOURCE' } }; - const programRules = [{ id: 'CTzRoPyvf8v', condition: 'true', displayName: 'Testing the functions!', programId: 'eBAyeGv0exc', programRuleActions: [{ id: 'isP0uvT24jf', displayContent: "d2:yearsBetween( '2010-01-28', V{event_date}) =", data: "d2:yearsBetween( '2010-01-28', V{event_date})", programRuleActionType: 'DISPLAYTEXT' }, { id: 'vQCRnX6w9pM', displayContent: 'd2:oizp( -10000000 ) =', data: 'd2:oizp( -10000000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'SYAL0GIDnxI', displayContent: 'display age = ', data: 'd2:hasValue(#{age}) && #{age}', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'Xa0tKyNk5YE', displayContent: 'org_unit = ', data: 'V{orgunit_code}', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'JXssEpbJdO2', displayContent: 'd2:right(#{age}, 3) = ', data: 'd2:hasValue(#{age}) && d2:right(#{age}, 3)', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'o0LLNIYsliy', displayContent: "d2:monthsBetween( '2020-01-28', V{event_date}) = ", data: "d2:monthsBetween( '2020-01-28', V{event_date})", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'k07KnI11Sf4', displayContent: 'd2:left(#{age}, 3) = ', data: 'd2:hasValue(#{age}) && d2:left(#{age}, 3)', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'OITs4nPfMQ3', displayContent: "d2:split('these-are-testing-values', '-', 2) = ", data: "d2:split('these-are-testing-values', '-', 2)", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'EzkFLDtAxCR', displayContent: 'd2:modulus( 12 , 100 ) = ', data: 'd2:modulus( 12 , 100 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'RCYEyOly0Mi', displayContent: "d2:countIfValue( #{gender}, 'Male' ) = ", data: "d2:countIfValue( #{gender}, 'Male' )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'bRnjbxIwIRd', displayContent: 'd2:round( 12.5 ) = ', data: 'd2:round( 12.5 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'BuEcHNoD98P', displayContent: 'd2:ceil(11.3) = ', data: 'd2:ceil(11.3)', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'Foc3PhzoAVr', displayContent: 'd2:count(#{age}) = ', data: 'd2:count(#{age})', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'QpeF2WDjwIV', displayContent: "d2:addDays( '2020-01-12', 5 ) = ", data: "d2:addDays( '2020-01-12', 5 )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'WJTjezLR4cJ', displayContent: "d2:weeksBetween('2020-01-28', V{event_date} ) = ", data: "d2:weeksBetween('2020-01-28', V{event_date} )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'YnE4dNJVF2P', displayContent: 'd2:zing( -2 ) = ', data: 'd2:zing( -2 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'bZsv2cUkbB7', displayContent: 'd2:floor( 11.5 ) =', data: 'd2:floor( 11.5 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'J8RxAbHlnO3', displayContent: 'd2:oizp( 10000000 ) = ', data: 'd2:oizp( 10000000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'NT1wojA2RdT', displayContent: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = ", data: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking')", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'NUGe7EUVouK', displayContent: "d2:substring('hello dhis 2', 6, 10) = ", data: "d2:substring('hello dhis 2', 6, 10)", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'Ma6nCIGrBrd', displayContent: "d2:length( 'dhis2 rocks' ) = ", data: "d2:length( 'dhis2 rocks' )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'RRSDsxWiUMc', displayContent: 'd2:round( 0 ) = ', data: 'd2:round( 0 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'QUe0Pks4ckc', displayContent: 'd2:countIfValue( #{age}, 1 ) = ', data: 'd2:countIfValue( #{age}, 1 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'sHaE1YI0ur2', displayContent: 'd2:zing( 1000 ) = ', data: 'd2:zing( 1000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'EojHcBMpW7q', displayContent: 'd2:hasValue( #{age} ) = ', data: 'd2:hasValue( #{age} )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }] }]; - const programRuleVariables = [{ id: 'RycV5uDi66i', dataElementId: 'qrur9Dvnyt5', displayName: 'age', programId: 'eBAyeGv0exc', programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', useNameForOptionSet: true }, { id: 'zINGRka3g9N', dataElementId: 'oZg33kd9taw', displayName: 'gender', programId: 'eBAyeGv0exc', programRuleVariableSourceType: 'DATAELEMENT_NEWEST_EVENT_PROGRAM', useNameForOptionSet: true }, { id: 'Zj7UnCAulEk.vV9UWAZohSf', displayName: 'Zj7UnCAulEk.vV9UWAZohSf', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', dataElementId: 'vV9UWAZohSf', programId: 'eBAyeGv0exc' }, { id: 'Zj7UnCAulEk.GieVkTxp4HH', displayName: 'Zj7UnCAulEk.GieVkTxp4HH', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', dataElementId: 'GieVkTxp4HH', programId: 'eBAyeGv0exc' }, { id: 'Zj7UnCAulEk.GieVkTxp4HH', displayName: 'Zj7UnCAulEk.GieVkTxp4HH', programRuleVariableSourceType: 'DATAELEMENT_CURRENT_EVENT', dataElementId: 'GieVkTxp4HH', programId: 'eBAyeGv0exc' }]; + const constants = [ + { id: 'Gfd3ppDfq8E', displayName: 'Commodity ordering overhead', value: 5 }, + { id: 'bCqvfPR02Im', displayName: 'Pi', value: 3.14 }, + ]; + const dataElementsInProgram = { + oZg33kd9taw: { id: 'oZg33kd9taw', valueType: 'TEXT', optionSetId: 'pC3N9N77UmT' }, + SWfdB5lX0fk: { id: 'SWfdB5lX0fk', valueType: 'BOOLEAN' }, + qrur9Dvnyt5: { id: 'qrur9Dvnyt5', valueType: 'INTEGER' }, + GieVkTxp4HH: { id: 'GieVkTxp4HH', valueType: 'NUMBER' }, + vV9UWAZohSf: { id: 'vV9UWAZohSf', valueType: 'INTEGER_POSITIVE' }, + eMyVanycQSC: { id: 'eMyVanycQSC', valueType: 'DATE' }, + K6uUAvq500H: { id: 'K6uUAvq500H', valueType: 'TEXT', optionSetId: 'eUZ79clX7y1' }, + msodh3rEMJa: { id: 'msodh3rEMJa', valueType: 'DATE' }, + S33cRBsnXPo: { id: 'S33cRBsnXPo', valueType: 'ORGANISATION_UNIT' }, + fWIAEtYVEGk: { id: 'fWIAEtYVEGk', valueType: 'TEXT', optionSetId: 'iDFPKpFTiVw' }, + ulD2zW0TIy2: { id: 'ulD2zW0TIy2', valueType: 'FILE_RESOURCE' }, + }; + const programRules = [ + { + id: 'CTzRoPyvf8v', + condition: 'true', + displayName: 'Testing the functions!', + programId: 'eBAyeGv0exc', + programRuleActions: [ + { + id: 'isP0uvT24jf', + displayContent: "d2:yearsBetween( '2010-01-28', V{event_date}) =", + data: "d2:yearsBetween( '2010-01-28', V{event_date})", + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'vQCRnX6w9pM', + displayContent: 'd2:oizp( -10000000 ) =', + data: 'd2:oizp( -10000000 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'SYAL0GIDnxI', + displayContent: 'display age = ', + data: 'd2:hasValue(#{age}) && #{age}', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'Xa0tKyNk5YE', + displayContent: 'org_unit = ', + data: 'V{orgunit_code}', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'JXssEpbJdO2', + displayContent: 'd2:right(#{age}, 3) = ', + data: 'd2:hasValue(#{age}) && d2:right(#{age}, 3)', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'o0LLNIYsliy', + displayContent: "d2:monthsBetween( '2020-01-28', V{event_date}) = ", + data: "d2:monthsBetween( '2020-01-28', V{event_date})", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'k07KnI11Sf4', + displayContent: 'd2:left(#{age}, 3) = ', + data: 'd2:hasValue(#{age}) && d2:left(#{age}, 3)', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'OITs4nPfMQ3', + displayContent: "d2:split('these-are-testing-values', '-', 2) = ", + data: "d2:split('these-are-testing-values', '-', 2)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'EzkFLDtAxCR', + displayContent: 'd2:modulus( 12 , 100 ) = ', + data: 'd2:modulus( 12 , 100 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'RCYEyOly0Mi', + displayContent: "d2:countIfValue( #{gender}, 'Male' ) = ", + data: "d2:countIfValue( #{gender}, 'Male' )", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'bRnjbxIwIRd', + displayContent: 'd2:round( 12.5 ) = ', + data: 'd2:round( 12.5 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'BuEcHNoD98P', + displayContent: 'd2:ceil(11.3) = ', + data: 'd2:ceil(11.3)', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'Foc3PhzoAVr', + displayContent: 'd2:count(#{age}) = ', + data: 'd2:count(#{age})', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'QpeF2WDjwIV', + displayContent: "d2:addDays( '2020-01-12', 5 ) = ", + data: "d2:addDays( '2020-01-12', 5 )", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'WJTjezLR4cJ', + displayContent: "d2:weeksBetween('2020-01-28', V{event_date} ) = ", + data: "d2:weeksBetween('2020-01-28', V{event_date} )", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'YnE4dNJVF2P', + displayContent: 'd2:zing( -2 ) = ', + data: 'd2:zing( -2 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'bZsv2cUkbB7', + displayContent: 'd2:floor( 11.5 ) =', + data: 'd2:floor( 11.5 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'J8RxAbHlnO3', + displayContent: 'd2:oizp( 10000000 ) = ', + data: 'd2:oizp( 10000000 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'NT1wojA2RdT', + displayContent: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = ", + data: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'NUGe7EUVouK', + displayContent: "d2:substring('hello dhis 2', 6, 10) = ", + data: "d2:substring('hello dhis 2', 6, 10)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'Ma6nCIGrBrd', + displayContent: "d2:length( 'dhis2 rocks' ) = ", + data: "d2:length( 'dhis2 rocks' )", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'RRSDsxWiUMc', + displayContent: 'd2:round( 0 ) = ', + data: 'd2:round( 0 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'QUe0Pks4ckc', + displayContent: 'd2:countIfValue( #{age}, 1 ) = ', + data: 'd2:countIfValue( #{age}, 1 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'sHaE1YI0ur2', + displayContent: 'd2:zing( 1000 ) = ', + data: 'd2:zing( 1000 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'EojHcBMpW7q', + displayContent: 'd2:hasValue( #{age} ) = ', + data: 'd2:hasValue( #{age} )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + ], + }, + ]; + const programRuleVariables = [ + { + id: 'RycV5uDi66i', + dataElementId: 'qrur9Dvnyt5', + displayName: 'age', + programId: 'eBAyeGv0exc', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, + useNameForOptionSet: true, + }, + { + id: 'zINGRka3g9N', + dataElementId: 'oZg33kd9taw', + displayName: 'gender', + programId: 'eBAyeGv0exc', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, + useNameForOptionSet: true, + }, + { + id: 'Zj7UnCAulEk.vV9UWAZohSf', + displayName: 'Zj7UnCAulEk.vV9UWAZohSf', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_PREVIOUS_EVENT, + dataElementId: 'vV9UWAZohSf', + programId: 'eBAyeGv0exc', + }, + { + id: 'Zj7UnCAulEk.GieVkTxp4HH', + displayName: 'Zj7UnCAulEk.GieVkTxp4HH', + programRuleVariableSourceType: variableSourceTypes.TEI_ATTRIBUTE, + dataElementId: 'GieVkTxp4HH', + programId: 'eBAyeGv0exc', + }, + { + id: 'Zj7UnCAulEk.GieVkTxp4HH', + displayName: 'Zj7UnCAulEk.GieVkTxp4HH', + programRuleVariableSourceType: 'UNKNOWN', + dataElementId: 'GieVkTxp4HH', + programId: 'eBAyeGv0exc', + }, + ]; const orgUnit = { id: 'DiszpKrYNg8', name: 'Ngelehun CHC', code: 'OU_559' }; - const optionSets = { pC3N9N77UmT: { id: 'pC3N9N77UmT', displayName: 'Gender', version: 0, valueType: 'TEXT', options: [{ id: 'rBvjJYbMCVx', displayName: 'Male', code: 'Male', translations: [] }, { id: 'Mnp3oXrpAbK', displayName: 'Female', code: 'Female', translations: [] }] } }; + const optionSets = { + pC3N9N77UmT: { + id: 'pC3N9N77UmT', + displayName: 'Gender', + version: 0, + valueType: 'TEXT', + options: [ + { id: 'rBvjJYbMCVx', displayName: 'Male', code: 'Male', translations: [] }, + { id: 'Mnp3oXrpAbK', displayName: 'Female', code: 'Female', translations: [] }, + ], + }, + }; // NOTE: in this test we dont use toMatchSnapshot instead we test again hardcoded values. Since the effects are plenty // here each time this way we can avoid mistakes in comparing snapshots @@ -377,95 +1857,410 @@ describe('Event rules engine effects with functions and effects', () => { [ {}, [ - { type: 'DISPLAYTEXT', displayText: { id: 'isP0uvT24jf', message: "d2:yearsBetween( '2010-01-28', V{event_date}) = " } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'vQCRnX6w9pM', message: 'd2:oizp( -10000000 ) = 0' } }, + { + type: 'DISPLAYTEXT', + displayText: { id: 'isP0uvT24jf', message: "d2:yearsBetween( '2010-01-28', V{event_date}) = " }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'vQCRnX6w9pM', message: 'd2:oizp( -10000000 ) = 0' }, + }, { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'SYAL0GIDnxI', message: 'display age = ' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Xa0tKyNk5YE', message: 'org_unit = OU_559' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'JXssEpbJdO2', message: 'd2:right(#{age}, 3) = ' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'o0LLNIYsliy', message: "d2:monthsBetween( '2020-01-28', V{event_date}) = " } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'k07KnI11Sf4', message: 'd2:left(#{age}, 3) = ' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'OITs4nPfMQ3', message: "d2:split('these-are-testing-values', '-', 2) = testing" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'EzkFLDtAxCR', message: 'd2:modulus( 12 , 100 ) = 12' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'RCYEyOly0Mi', message: "d2:countIfValue( #{gender}, 'Male' ) = 0" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'bRnjbxIwIRd', message: 'd2:round( 12.5 ) = 13' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'BuEcHNoD98P', message: 'd2:ceil(11.3) = 12' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Foc3PhzoAVr', message: 'd2:count(#{age}) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'QpeF2WDjwIV', message: "d2:addDays( '2020-01-12', 5 ) = 2020-01-17" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'WJTjezLR4cJ', message: "d2:weeksBetween('2020-01-28', V{event_date} ) = " } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'YnE4dNJVF2P', message: 'd2:zing( -2 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'bZsv2cUkbB7', message: 'd2:floor( 11.5 ) = 11' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'J8RxAbHlnO3', message: 'd2:oizp( 10000000 ) = 1' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'NT1wojA2RdT', message: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = dhis2isrocking" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'NUGe7EUVouK', message: "d2:substring('hello dhis 2', 6, 10) = dhis" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Ma6nCIGrBrd', message: "d2:length( 'dhis2 rocks' ) = 11" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'RRSDsxWiUMc', message: 'd2:round( 0 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'QUe0Pks4ckc', message: 'd2:countIfValue( #{age}, 1 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'sHaE1YI0ur2', message: 'd2:zing( 1000 ) = 1000' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'EojHcBMpW7q', message: 'd2:hasValue( #{age} ) = ' } }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Xa0tKyNk5YE', message: 'org_unit = OU_559' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'JXssEpbJdO2', message: 'd2:right(#{age}, 3) = ' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'o0LLNIYsliy', message: "d2:monthsBetween( '2020-01-28', V{event_date}) = " }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'k07KnI11Sf4', message: 'd2:left(#{age}, 3) = ' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'OITs4nPfMQ3', + message: "d2:split('these-are-testing-values', '-', 2) = testing", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'EzkFLDtAxCR', message: 'd2:modulus( 12 , 100 ) = 12' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'RCYEyOly0Mi', message: "d2:countIfValue( #{gender}, 'Male' ) = 0" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'bRnjbxIwIRd', message: 'd2:round( 12.5 ) = 13' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'BuEcHNoD98P', message: 'd2:ceil(11.3) = 12' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Foc3PhzoAVr', message: 'd2:count(#{age}) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'QpeF2WDjwIV', message: "d2:addDays( '2020-01-12', 5 ) = 2020-01-17" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'WJTjezLR4cJ', message: "d2:weeksBetween('2020-01-28', V{event_date} ) = " }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'YnE4dNJVF2P', message: 'd2:zing( -2 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'bZsv2cUkbB7', message: 'd2:floor( 11.5 ) = 11' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'J8RxAbHlnO3', message: 'd2:oizp( 10000000 ) = 1' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'NT1wojA2RdT', + message: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = dhis2isrocking", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'NUGe7EUVouK', message: "d2:substring('hello dhis 2', 6, 10) = dhis" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Ma6nCIGrBrd', message: "d2:length( 'dhis2 rocks' ) = 11" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'RRSDsxWiUMc', message: 'd2:round( 0 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'QUe0Pks4ckc', message: 'd2:countIfValue( #{age}, 1 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'sHaE1YI0ur2', message: 'd2:zing( 1000 ) = 1000' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'EojHcBMpW7q', message: 'd2:hasValue( #{age} ) = ' }, + }, ], ], [ { - oZg33kd9taw: 'Male', qrur9Dvnyt5: 0, occurredAt: '2020-04-30T22:00:00.000Z', + oZg33kd9taw: 'Male', + qrur9Dvnyt5: 0, + occurredAt: '2020-04-30T22:00:00.000Z', }, [ - { type: 'DISPLAYTEXT', displayText: { id: 'isP0uvT24jf', message: "d2:yearsBetween( '2010-01-28', V{event_date}) = 10" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'vQCRnX6w9pM', message: 'd2:oizp( -10000000 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'SYAL0GIDnxI', message: 'display age = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Xa0tKyNk5YE', message: 'org_unit = OU_559' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'JXssEpbJdO2', message: 'd2:right(#{age}, 3) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'o0LLNIYsliy', message: "d2:monthsBetween( '2020-01-28', V{event_date}) = 3" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'k07KnI11Sf4', message: 'd2:left(#{age}, 3) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'OITs4nPfMQ3', message: "d2:split('these-are-testing-values', '-', 2) = testing" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'EzkFLDtAxCR', message: 'd2:modulus( 12 , 100 ) = 12' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'RCYEyOly0Mi', message: "d2:countIfValue( #{gender}, 'Male' ) = 1" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'bRnjbxIwIRd', message: 'd2:round( 12.5 ) = 13' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'BuEcHNoD98P', message: 'd2:ceil(11.3) = 12' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Foc3PhzoAVr', message: 'd2:count(#{age}) = 1' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'QpeF2WDjwIV', message: "d2:addDays( '2020-01-12', 5 ) = 2020-01-17" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'WJTjezLR4cJ', message: "d2:weeksBetween('2020-01-28', V{event_date} ) = 13" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'YnE4dNJVF2P', message: 'd2:zing( -2 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'bZsv2cUkbB7', message: 'd2:floor( 11.5 ) = 11' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'J8RxAbHlnO3', message: 'd2:oizp( 10000000 ) = 1' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'NT1wojA2RdT', message: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = dhis2isrocking" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'NUGe7EUVouK', message: "d2:substring('hello dhis 2', 6, 10) = dhis" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Ma6nCIGrBrd', message: "d2:length( 'dhis2 rocks' ) = 11" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'RRSDsxWiUMc', message: 'd2:round( 0 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'QUe0Pks4ckc', message: 'd2:countIfValue( #{age}, 1 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'sHaE1YI0ur2', message: 'd2:zing( 1000 ) = 1000' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'EojHcBMpW7q', message: 'd2:hasValue( #{age} ) = true' } }, + { + type: 'DISPLAYTEXT', + displayText: { id: 'isP0uvT24jf', message: "d2:yearsBetween( '2010-01-28', V{event_date}) = 10" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'vQCRnX6w9pM', message: 'd2:oizp( -10000000 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'SYAL0GIDnxI', message: 'display age = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Xa0tKyNk5YE', message: 'org_unit = OU_559' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'JXssEpbJdO2', message: 'd2:right(#{age}, 3) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'o0LLNIYsliy', message: "d2:monthsBetween( '2020-01-28', V{event_date}) = 3" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'k07KnI11Sf4', message: 'd2:left(#{age}, 3) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'OITs4nPfMQ3', + message: "d2:split('these-are-testing-values', '-', 2) = testing", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'EzkFLDtAxCR', message: 'd2:modulus( 12 , 100 ) = 12' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'RCYEyOly0Mi', message: "d2:countIfValue( #{gender}, 'Male' ) = 1" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'bRnjbxIwIRd', message: 'd2:round( 12.5 ) = 13' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'BuEcHNoD98P', message: 'd2:ceil(11.3) = 12' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Foc3PhzoAVr', message: 'd2:count(#{age}) = 1' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'QpeF2WDjwIV', message: "d2:addDays( '2020-01-12', 5 ) = 2020-01-17" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'WJTjezLR4cJ', message: "d2:weeksBetween('2020-01-28', V{event_date} ) = 13" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'YnE4dNJVF2P', message: 'd2:zing( -2 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'bZsv2cUkbB7', message: 'd2:floor( 11.5 ) = 11' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'J8RxAbHlnO3', message: 'd2:oizp( 10000000 ) = 1' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'NT1wojA2RdT', + message: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = dhis2isrocking", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'NUGe7EUVouK', message: "d2:substring('hello dhis 2', 6, 10) = dhis" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Ma6nCIGrBrd', message: "d2:length( 'dhis2 rocks' ) = 11" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'RRSDsxWiUMc', message: 'd2:round( 0 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'QUe0Pks4ckc', message: 'd2:countIfValue( #{age}, 1 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'sHaE1YI0ur2', message: 'd2:zing( 1000 ) = 1000' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'EojHcBMpW7q', message: 'd2:hasValue( #{age} ) = true' }, + }, ], ], [ { - oZg33kd9taw: 'Male', qrur9Dvnyt5: 1000000000, occurredAt: '2020-04-30T22:00:00.000Z', + oZg33kd9taw: 'Male', + qrur9Dvnyt5: 1000000000, + occurredAt: '2020-04-30T22:00:00.000Z', }, [ - { type: 'DISPLAYTEXT', displayText: { id: 'isP0uvT24jf', message: "d2:yearsBetween( '2010-01-28', V{event_date}) = 10" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'vQCRnX6w9pM', message: 'd2:oizp( -10000000 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'SYAL0GIDnxI', message: 'display age = 1000000000' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Xa0tKyNk5YE', message: 'org_unit = OU_559' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'JXssEpbJdO2', message: 'd2:right(#{age}, 3) = 000' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'o0LLNIYsliy', message: "d2:monthsBetween( '2020-01-28', V{event_date}) = 3" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'k07KnI11Sf4', message: 'd2:left(#{age}, 3) = 100' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'OITs4nPfMQ3', message: "d2:split('these-are-testing-values', '-', 2) = testing" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'EzkFLDtAxCR', message: 'd2:modulus( 12 , 100 ) = 12' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'RCYEyOly0Mi', message: "d2:countIfValue( #{gender}, 'Male' ) = 1" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'bRnjbxIwIRd', message: 'd2:round( 12.5 ) = 13' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'BuEcHNoD98P', message: 'd2:ceil(11.3) = 12' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Foc3PhzoAVr', message: 'd2:count(#{age}) = 1' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'QpeF2WDjwIV', message: "d2:addDays( '2020-01-12', 5 ) = 2020-01-17" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'WJTjezLR4cJ', message: "d2:weeksBetween('2020-01-28', V{event_date} ) = 13" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'YnE4dNJVF2P', message: 'd2:zing( -2 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'bZsv2cUkbB7', message: 'd2:floor( 11.5 ) = 11' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'J8RxAbHlnO3', message: 'd2:oizp( 10000000 ) = 1' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'NT1wojA2RdT', message: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = dhis2isrocking" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'NUGe7EUVouK', message: "d2:substring('hello dhis 2', 6, 10) = dhis" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Ma6nCIGrBrd', message: "d2:length( 'dhis2 rocks' ) = 11" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'RRSDsxWiUMc', message: 'd2:round( 0 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'QUe0Pks4ckc', message: 'd2:countIfValue( #{age}, 1 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'sHaE1YI0ur2', message: 'd2:zing( 1000 ) = 1000' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'EojHcBMpW7q', message: 'd2:hasValue( #{age} ) = true' } }, + { + type: 'DISPLAYTEXT', + displayText: { id: 'isP0uvT24jf', message: "d2:yearsBetween( '2010-01-28', V{event_date}) = 10" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'vQCRnX6w9pM', message: 'd2:oizp( -10000000 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'SYAL0GIDnxI', message: 'display age = 1000000000' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Xa0tKyNk5YE', message: 'org_unit = OU_559' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'JXssEpbJdO2', message: 'd2:right(#{age}, 3) = 000' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'o0LLNIYsliy', message: "d2:monthsBetween( '2020-01-28', V{event_date}) = 3" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'k07KnI11Sf4', message: 'd2:left(#{age}, 3) = 100' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'OITs4nPfMQ3', + message: "d2:split('these-are-testing-values', '-', 2) = testing", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'EzkFLDtAxCR', message: 'd2:modulus( 12 , 100 ) = 12' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'RCYEyOly0Mi', message: "d2:countIfValue( #{gender}, 'Male' ) = 1" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'bRnjbxIwIRd', message: 'd2:round( 12.5 ) = 13' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'BuEcHNoD98P', message: 'd2:ceil(11.3) = 12' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Foc3PhzoAVr', message: 'd2:count(#{age}) = 1' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'QpeF2WDjwIV', message: "d2:addDays( '2020-01-12', 5 ) = 2020-01-17" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'WJTjezLR4cJ', message: "d2:weeksBetween('2020-01-28', V{event_date} ) = 13" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'YnE4dNJVF2P', message: 'd2:zing( -2 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'bZsv2cUkbB7', message: 'd2:floor( 11.5 ) = 11' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'J8RxAbHlnO3', message: 'd2:oizp( 10000000 ) = 1' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'NT1wojA2RdT', + message: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = dhis2isrocking", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'NUGe7EUVouK', message: "d2:substring('hello dhis 2', 6, 10) = dhis" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Ma6nCIGrBrd', message: "d2:length( 'dhis2 rocks' ) = 11" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'RRSDsxWiUMc', message: 'd2:round( 0 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'QUe0Pks4ckc', message: 'd2:countIfValue( #{age}, 1 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'sHaE1YI0ur2', message: 'd2:zing( 1000 ) = 1000' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'EojHcBMpW7q', message: 'd2:hasValue( #{age} ) = true' }, + }, ], ], ])('where functions take place', (currentEvent, expected) => { @@ -485,8 +2280,71 @@ describe('Event rules engine effects with functions and effects', () => { describe('Event rules engine effects with functions and effects', () => { // these variables are shared between each test const constants = []; - const dataElementsInProgram = { oZg33kd9taw: { id: 'oZg33kd9taw', valueType: 'TEXT', optionSetId: 'pC3N9N77UmT' }, SWfdB5lX0fk: { id: 'SWfdB5lX0fk', valueType: 'BOOLEAN' }, qrur9Dvnyt5: { id: 'qrur9Dvnyt5', valueType: 'INTEGER' }, GieVkTxp4HH: { id: 'GieVkTxp4HH', valueType: 'NUMBER' }, vV9UWAZohSf: { id: 'vV9UWAZohSf', valueType: 'INTEGER_POSITIVE' }, eMyVanycQSC: { id: 'eMyVanycQSC', valueType: 'DATE' }, K6uUAvq500H: { id: 'K6uUAvq500H', valueType: 'TEXT', optionSetId: 'eUZ79clX7y1' }, msodh3rEMJa: { id: 'msodh3rEMJa', valueType: 'DATE' }, S33cRBsnXPo: { id: 'S33cRBsnXPo', valueType: 'ORGANISATION_UNIT' }, fWIAEtYVEGk: { id: 'fWIAEtYVEGk', valueType: 'TEXT', optionSetId: 'iDFPKpFTiVw' }, ulD2zW0TIy2: { id: 'ulD2zW0TIy2', valueType: 'FILE_RESOURCE' } }; - const programRules = [{ id: 'cq1dwUY4lVU', condition: 'true', displayName: 'testing the z-scores', programId: 'eBAyeGv0exc', programRuleActions: [{ id: 'I6pDcSm2m0g', displayContent: "d2:zScoreWFA( 20, 15, 'M' ) = ", data: "d2:zScoreWFA( 20, 15, 'M' )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'No0T9TgN1Px', displayContent: "d2:zScoreWFH( 100, 20, 'M' ) = ", data: "d2:zScoreWFH( 100, 20, 'M' )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'n1GUxR8fShY', displayContent: "d2:zScoreHFA( 15, 20, 'F' ) =", data: "d2:zScoreHFA( 15, 20, 'F' ) ", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'QJlZHo0GoVK', displayContent: "d2:zScoreWFH( 100, 20, 'F' ) = ", data: "d2:zScoreWFH( 100, 20, 'F' ) ", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'ItuKGBUuJgK', displayContent: "d2:zScoreWFA( 20, 15, 'F' ) = ", data: "d2:zScoreWFA( 20, 15, 'F' )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, { id: 'uhyaCDzzivm', displayContent: "d2:zScoreHFA( 15, 20, 'M' ) =", data: "d2:zScoreHFA( 15, 20, 'M' )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }] }]; + const dataElementsInProgram = { + oZg33kd9taw: { id: 'oZg33kd9taw', valueType: 'TEXT', optionSetId: 'pC3N9N77UmT' }, + SWfdB5lX0fk: { id: 'SWfdB5lX0fk', valueType: 'BOOLEAN' }, + qrur9Dvnyt5: { id: 'qrur9Dvnyt5', valueType: 'INTEGER' }, + GieVkTxp4HH: { id: 'GieVkTxp4HH', valueType: 'NUMBER' }, + vV9UWAZohSf: { id: 'vV9UWAZohSf', valueType: 'INTEGER_POSITIVE' }, + eMyVanycQSC: { id: 'eMyVanycQSC', valueType: 'DATE' }, + K6uUAvq500H: { id: 'K6uUAvq500H', valueType: 'TEXT', optionSetId: 'eUZ79clX7y1' }, + msodh3rEMJa: { id: 'msodh3rEMJa', valueType: 'DATE' }, + S33cRBsnXPo: { id: 'S33cRBsnXPo', valueType: 'ORGANISATION_UNIT' }, + fWIAEtYVEGk: { id: 'fWIAEtYVEGk', valueType: 'TEXT', optionSetId: 'iDFPKpFTiVw' }, + ulD2zW0TIy2: { id: 'ulD2zW0TIy2', valueType: 'FILE_RESOURCE' }, + }; + const programRules = [ + { + id: 'cq1dwUY4lVU', + condition: 'true', + displayName: 'testing the z-scores', + programId: 'eBAyeGv0exc', + programRuleActions: [ + { + id: 'I6pDcSm2m0g', + displayContent: "d2:zScoreWFA( 20, 15, 'M' ) = ", + data: "d2:zScoreWFA( 20, 15, 'M' )", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'No0T9TgN1Px', + displayContent: "d2:zScoreWFH( 100, 20, 'M' ) = ", + data: "d2:zScoreWFH( 100, 20, 'M' )", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'n1GUxR8fShY', + displayContent: "d2:zScoreHFA( 15, 20, 'F' ) =", + data: "d2:zScoreHFA( 15, 20, 'F' ) ", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'QJlZHo0GoVK', + displayContent: "d2:zScoreWFH( 100, 20, 'F' ) = ", + data: "d2:zScoreWFH( 100, 20, 'F' ) ", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'ItuKGBUuJgK', + displayContent: "d2:zScoreWFA( 20, 15, 'F' ) = ", + data: "d2:zScoreWFA( 20, 15, 'F' )", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'uhyaCDzzivm', + displayContent: "d2:zScoreHFA( 15, 20, 'M' ) =", + data: "d2:zScoreHFA( 15, 20, 'M' )", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + ], + }, + ]; const programRuleVariables = []; const orgUnit = { id: 'DiszpKrYNg8', name: 'Ngelehun CHC' }; const optionSets = {}; @@ -505,12 +2363,36 @@ describe('Event rules engine effects with functions and effects', () => { // then expect(rulesEffects).toEqual([ - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'I6pDcSm2m0g', message: "d2:zScoreWFA( 20, 15, 'M' ) = 2.47" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'No0T9TgN1Px', message: "d2:zScoreWFH( 100, 20, 'M' ) = 3.5" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'n1GUxR8fShY', message: "d2:zScoreHFA( 15, 20, 'F' ) = -3.5" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'QJlZHo0GoVK', message: "d2:zScoreWFH( 100, 20, 'F' ) = 2.84" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'ItuKGBUuJgK', message: "d2:zScoreWFA( 20, 15, 'F' ) = 2.65" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'uhyaCDzzivm', message: "d2:zScoreHFA( 15, 20, 'M' ) = -3.5" } }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'I6pDcSm2m0g', message: "d2:zScoreWFA( 20, 15, 'M' ) = 2.47" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'No0T9TgN1Px', message: "d2:zScoreWFH( 100, 20, 'M' ) = 3.5" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'n1GUxR8fShY', message: "d2:zScoreHFA( 15, 20, 'F' ) = -3.5" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'QJlZHo0GoVK', message: "d2:zScoreWFH( 100, 20, 'F' ) = 2.84" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'ItuKGBUuJgK', message: "d2:zScoreWFA( 20, 15, 'F' ) = 2.65" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'uhyaCDzzivm', message: "d2:zScoreHFA( 15, 20, 'M' ) = -3.5" }, + }, ]); }); }); @@ -519,7 +2401,11 @@ describe('Event rules engine effects with functions and effects', () => { describe('Event rules engine', () => { // these variables are shared between each test const constants = []; - const dataElementsInProgram = { oZg33kd9taw: { id: 'oZg33kd9taw', valueType: 'BOOLEAN' }, SWfdB5lX0fk: { id: 'SWfdB5lX0fk', valueType: 'TRUE_ONLY' }, qrur9Dvnyt5: { id: 'qrur9Dvnyt5', valueType: 'NUMBER' } }; + const dataElementsInProgram = { + oZg33kd9taw: { id: 'oZg33kd9taw', valueType: 'BOOLEAN' }, + SWfdB5lX0fk: { id: 'SWfdB5lX0fk', valueType: 'TRUE_ONLY' }, + qrur9Dvnyt5: { id: 'qrur9Dvnyt5', valueType: 'NUMBER' }, + }; const programRuleVariables = []; const orgUnit = { id: 'DiszpKrYNg8', name: 'Ngelehun CHC' }; const optionSets = {}; @@ -527,50 +2413,110 @@ describe('Event rules engine', () => { describe.each([ [ - [{ - id: 'cq1dwUY4lVU', - condition: 'true', - displayName: 'testing assign actions', - programId: 'eBAyeGv0exc', - programRuleActions: [ - { id: 'lJOYxhjupxz', data: 'true', dataElementId: 'oZg33kd9taw', programRuleActionType: 'ASSIGN' }, - { id: 'lJOYxhjupx1', data: 'true', dataElementId: 'SWfdB5lX0fk', programRuleActionType: 'ASSIGN' }, - { id: 'lJOYxhjupx2', data: '6', dataElementId: 'qrur9Dvnyt5', programRuleActionType: 'ASSIGN' }, - ], - }], [ - { type: 'ASSIGN', id: 'oZg33kd9taw', value: 'true', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'ASSIGN', id: 'SWfdB5lX0fk', value: 'true', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'ASSIGN', id: 'qrur9Dvnyt5', value: '6', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, + { + id: 'cq1dwUY4lVU', + condition: 'true', + displayName: 'testing assign actions', + programId: 'eBAyeGv0exc', + programRuleActions: [ + { + id: 'lJOYxhjupxz', + data: 'true', + dataElementId: 'oZg33kd9taw', + programRuleActionType: 'ASSIGN', + }, + { + id: 'lJOYxhjupx1', + data: 'true', + dataElementId: 'SWfdB5lX0fk', + programRuleActionType: 'ASSIGN', + }, + { id: 'lJOYxhjupx2', data: '6', dataElementId: 'qrur9Dvnyt5', programRuleActionType: 'ASSIGN' }, + ], + }, ], - ], [ - [{ - id: 'cq1dwUY4lVU', - condition: 'true', - displayName: 'testing assign actions', - programId: 'eBAyeGv0exc', - programRuleActions: [ - { id: 'lJOYxhjupxz', data: '', dataElementId: 'oZg33kd9taw', programRuleActionType: 'ASSIGN' }, - { id: 'lJOYxhjupx1', data: '', dataElementId: 'SWfdB5lX0fk', programRuleActionType: 'ASSIGN' }, - { id: 'lJOYxhjupx2', data: '', dataElementId: 'qrur9Dvnyt5', programRuleActionType: 'ASSIGN' }, - ], - }], [ - { type: 'ASSIGN', id: 'oZg33kd9taw', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'ASSIGN', id: 'SWfdB5lX0fk', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, - { type: 'ASSIGN', id: 'qrur9Dvnyt5', value: null, targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }, + { + type: 'ASSIGN', + id: 'oZg33kd9taw', + value: 'true', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'ASSIGN', + id: 'SWfdB5lX0fk', + value: 'true', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'ASSIGN', + id: 'qrur9Dvnyt5', + value: '6', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + ], + ], + [ + [ + { + id: 'cq1dwUY4lVU', + condition: 'true', + displayName: 'testing assign actions', + programId: 'eBAyeGv0exc', + programRuleActions: [ + { id: 'lJOYxhjupxz', data: '', dataElementId: 'oZg33kd9taw', programRuleActionType: 'ASSIGN' }, + { id: 'lJOYxhjupx1', data: '', dataElementId: 'SWfdB5lX0fk', programRuleActionType: 'ASSIGN' }, + { id: 'lJOYxhjupx2', data: '', dataElementId: 'qrur9Dvnyt5', programRuleActionType: 'ASSIGN' }, + ], + }, + ], + [ + { + type: 'ASSIGN', + id: 'oZg33kd9taw', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'ASSIGN', + id: 'SWfdB5lX0fk', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + { + type: 'ASSIGN', + id: 'qrur9Dvnyt5', + value: null, + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, + ], + ], + [ + [ + { + id: 'cq1dwUY4lVU', + condition: 'true', + displayName: 'testing assign actions', + programId: 'eBAyeGv0exc', + programRuleActions: [ + { + id: 'lJOYxhjupxz', + data: 'false', + dataElementId: 'oZg33kd9taw', + programRuleActionType: 'ASSIGN', + }, + ], + }, + ], + [ + { + type: 'ASSIGN', + id: 'oZg33kd9taw', + value: 'false', + targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT, + }, ], - ], [ - [{ - id: 'cq1dwUY4lVU', - condition: 'true', - displayName: 'testing assign actions', - programId: 'eBAyeGv0exc', - programRuleActions: [ - { id: 'lJOYxhjupxz', data: 'false', dataElementId: 'oZg33kd9taw', programRuleActionType: 'ASSIGN' }, - ], - }], - [{ type: 'ASSIGN', id: 'oZg33kd9taw', value: 'false', targetDataType: rulesEngineEffectTargetDataTypes.DATA_ELEMENT }], ], ])('where assign actions are triggered', (programRules, expected) => { test(`with given value(s): ${JSON.stringify(programRules)}`, () => { @@ -586,3 +2532,393 @@ describe('Event rules engine', () => { }); }); }); + +describe('Assign effects', () => { + // these variables are shared between each test + const constants = []; + const dataElementsInProgram = { + qrur9Dvnyt5: { id: 'qrur9Dvnyt5', valueType: 'NUMBER' }, + hrur9Dvnyt5: { id: 'hrur9Dvnyt5', valueType: 'TRUE_ONLY' }, + g67r9Dvnyt5: { id: 'g67r9Dvnyt5', valueType: 'TRUE_ONLY' }, + sfer9Dvnyt5: { id: 'sfer9Dvnyt5', valueType: 'LONG_TEXT' }, + oZg33kd9taw: { id: 'oZg33kd9taw', valueType: 'BOOLEAN' }, + hjrr9Dvnyt5: { id: 'hjrr9Dvnyt5', valueType: 'LETTER' }, + lowr9Dvnyt5: { id: 'lowr9Dvnyt5', valueType: 'PHONE_NUMBER' }, + kht29Dvnyt5: { id: 'kht29Dvnyt5', valueType: 'EMAIL' }, + hyrt9Dvnyt5: { id: 'hyrt9Dvnyt5', valueType: 'DATE' }, + loir9Dvnyt5: { id: 'loir9Dvnyt5', valueType: 'DATETIME' }, + sldkjfjfjfe: { id: 'sldkjfjfjfe', valueType: 'TIME' }, + kyt49Dvnyt5: { id: 'kyt49Dvnyt5', valueType: 'PERCENTAGE' }, + kiyu9Dvnyt5: { id: 'kiyu9Dvnyt5', valueType: 'INTEGER' }, + frt59Dvnyt5: { id: 'frt59Dvnyt5', valueType: 'INTEGER_POSITIVE' }, + jhty9Dvnyt5: { id: 'jhty9Dvnyt5', valueType: 'INTEGER_NEGATIVE' }, + jhrr9Dvnyt5: { id: 'jhrr9Dvnyt5', valueType: 'INTEGER_ZERO_OR_POSITIVE' }, + plor9Dvnyt5: { id: 'plor9Dvnyt5', valueType: 'USERNAME' }, + frg39Dvnyt5: { id: 'frg39Dvnyt5', valueType: 'COORDINATE' }, + kjyu9Dvnyt5: { id: 'kjyu9Dvnyt5', valueType: 'ORGANISATION_UNIT' }, + kjfr9Dvnyt5: { id: 'kjfr9Dvnyt5', valueType: 'AGE' }, + lqwr9Dvnyt5: { id: 'lqwr9Dvnyt5', valueType: 'URL' }, + mjus9Dvnyt5: { id: 'mjus9Dvnyt5', valueType: 'FILE_RESOURCE' }, + fgrr9Dvnyt5: { id: 'fgrr9Dvnyt5', valueType: 'IMAGE' }, + oZ3fhkd9taw: { id: 'oZ3fhkd9taw', valueType: 'UNKNOWN' }, + }; + const orgUnit = { id: 'DiszpKrYNg8', name: 'Ngelehun CHC' }; + const optionSets = {}; + const currentEvent = {}; + + test('Assign effect corner cases', () => { + const programRules = [ + { + id: 'cq1dwUY4lVU', + condition: 'true', + displayName: 'testing assign actions', + programId: 'eBAyeGv0exc', + programRuleActions: [ + { + id: 'lJOYxhjupx2', + data: "'string'", + dataElementId: 'qrur9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { id: 'lJOYxkjupx2', data: "'10'", dataElementId: 'qrur9Dvnyt5', programRuleActionType: 'ASSIGN' }, + { + id: 'lJhYxhjupxz', + data: "'string'", + dataElementId: 'oZg33kd9taw', + programRuleActionType: 'ASSIGN', + }, + { + id: 'lJfYxhjupxz', + data: "'string'", + dataElementId: 'oZ3fhkd9taw', + programRuleActionType: 'ASSIGN', + }, + { + id: 'sdfsd34567h', + data: 'value', + dataElementId: 'hrur9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'g67rgyvnyt5', + data: null, + dataElementId: 'g67r9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'fsafYxhjux2', + data: "'LONG_TEXT'", + dataElementId: 'sfer9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'o8rr9Dvnyt5', + data: "'LETTER'", + dataElementId: 'hjrr9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'lsdjlks4ffs', + data: '34535353', + dataElementId: 'lowr9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'hsjd7574jfj', + data: 'test@test.com', + dataElementId: 'kht29Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'sdf57549jco', + data: '11-11-2013', + dataElementId: 'hyrt9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'gtir9Dvnyt5', + data: '2021-05-31', + dataElementId: 'loir9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 's678jfjfjfe', + data: '11:11', + dataElementId: 'sldkjfjfjfe', + programRuleActionType: 'ASSIGN', + }, + { + id: 'sdhsfjks35f', + data: '30', + dataElementId: 'kyt49Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'kjosfjks35f', + data: '30', + dataElementId: 'kiyu9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'kjyofjks35f', + data: '30', + dataElementId: 'frt59Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'jhkj9Dvnyt5', + data: '-30', + dataElementId: 'jhty9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'hjyur9Dvnyt5', + data: '-30', + dataElementId: 'jhrr9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'lopr9Dvnyt5', + data: 'username', + dataElementId: 'plor9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'kjy39Dvnyt5', + data: "'12,4343'", + dataElementId: 'frg39Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'loiu9Dvnyt5', + data: 'ORGANISATION_UNIT', + dataElementId: 'kjyu9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'kjfr9Dvnyt5', + data: 'Invalid date', + dataElementId: 'kjfr9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'hywr9Dvnyt5', + data: 'urlPath', + dataElementId: 'lqwr9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'gt769Dvnyt5', + data: 'FILE_RESOURCE', + dataElementId: 'mjus9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + { + id: 'gt659Dvnyt5', + data: 'IMAGE', + dataElementId: 'fgrr9Dvnyt5', + programRuleActionType: 'ASSIGN', + }, + ], + }, + ]; + const programRuleVariables = []; + systemSettingsStore.set({ dateFormat: 'YYYY-MM-DD' }); + // when + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + currentEvent, + dataElements: dataElementsInProgram, + selectedOrgUnit: orgUnit, + optionSets, + }); + + // then + expect(rulesEffects).toEqual([ + { type: 'ASSIGN', id: 'qrur9Dvnyt5', value: null, targetDataType: 'dataElement' }, + { type: 'ASSIGN', id: 'qrur9Dvnyt5', value: '10', targetDataType: 'dataElement' }, + { type: 'ASSIGN', id: 'oZg33kd9taw', value: 'false', targetDataType: 'dataElement' }, + { type: 'ASSIGN', id: 'oZ3fhkd9taw', value: '', targetDataType: 'dataElement' }, + { + id: 'hrur9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: 'false', + }, + { + id: 'g67r9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: null, + }, + { + id: 'sfer9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: 'LONG_TEXT', + }, + { + id: 'hjrr9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: 'LETTER', + }, + { + id: 'lowr9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: 34535353, + }, + { + id: 'kht29Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: false, + }, + { + id: 'hyrt9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: '2013-01-01', + }, + { + id: 'loir9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: { + date: 'Invalid date', + time: 'Invalid date', + }, + }, + { + id: 'sldkjfjfjfe', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: false, + }, + { + id: 'kyt49Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: '30', + }, + { + id: 'kiyu9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: '30', + }, + { + id: 'frt59Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: '30', + }, + { + id: 'jhty9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: '-30', + }, + { + id: 'jhrr9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: '-30', + }, + { + id: 'plor9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: '', + }, + { + id: 'frg39Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: { + latitude: 2, + longitude: 434, + }, + }, + { + id: 'kjyu9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: '', + }, + { + id: 'kjfr9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: { + date: 'Invalid date', + days: 'NaN', + months: 'NaN', + years: 'NaN', + }, + }, + { + id: 'lqwr9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: false, + }, + { + id: 'mjus9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: '', + }, + { + id: 'fgrr9Dvnyt5', + targetDataType: 'dataElement', + type: 'ASSIGN', + value: '', + }, + ]); + }); + + test('Assign effect with the program rule variable id found in the content key', () => { + const programRules = [ + { + id: 'cq1dwUY4lVU', + condition: 'true', + displayName: 'testing assign actions', + programId: 'eBAyeGv0exc', + programRuleActions: [ + { + id: 'lJOYxhjupx2', + data: 'rowExpresion', + dataElementId: 'qrur9Dvnyt5', + programRuleActionType: 'ASSIGN', + content: 'Hemoglobin value lower than normal RycV5uDi66i', + }, + ], + }, + ]; + const programRuleVariables = [ + { + id: 'RycV5uDi66i', + dataElementId: 'qrur9Dvnyt5', + displayName: 'age', + programId: 'eBAyeGv0exc', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, + useNameForOptionSet: true, + }, + ]; + // when + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + currentEvent, + dataElements: dataElementsInProgram, + selectedOrgUnit: orgUnit, + optionSets, + }); + + // then + expect(rulesEffects).toEqual([ + { type: 'ASSIGN', id: 'qrur9Dvnyt5', value: 'false', targetDataType: 'dataElement' }, + ]); + }); +}); diff --git a/src/core_modules/capture-core/rules/__tests__/rulesEffectsForTrackerProgram.test.js b/src/core_modules/capture-core/rules/__tests__/rulesEffectsForTrackerProgram.test.js index bbd2514ae8..213c6c5abf 100644 --- a/src/core_modules/capture-core/rules/__tests__/rulesEffectsForTrackerProgram.test.js +++ b/src/core_modules/capture-core/rules/__tests__/rulesEffectsForTrackerProgram.test.js @@ -1,78 +1,865 @@ +import { variableSourceTypes } from '@dhis2/rules-engine-javascript'; import { rulesEngine } from '../rulesEngine'; test('expressions with d2Functions in tracker program', () => { // given const constants = []; - const trackedEntityAttributes = { w75KJ2mc4zz: { id: 'w75KJ2mc4zz', valueType: 'TEXT' }, zDhUuAYrxNC: { id: 'zDhUuAYrxNC', valueType: 'TEXT' }, cejWyOfXge6: { id: 'cejWyOfXge6', valueType: 'TEXT', optionSetId: 'pC3N9N77UmT' }, lZGmxYbs97q: { id: 'lZGmxYbs97q', valueType: 'NUMBER' } }; - const programRules = [{ - id: 'g82J3xsNer9', - condition: 'true', - displayName: 'Testing the functions!', - programId: 'IpHINAT79UW', - programRuleActions: [ - { id: 'Eeb7Ixr4Pvx', displayContent: "d2:left('dhis', 3) = ", data: "d2:left('dhis', 3)", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'lbIGJYVI57u', displayContent: 'd2:zing( -2 ) = ', data: 'd2:zing( -2 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'kwKhYpVRDyj', displayContent: "d2:monthsBetween( '2020-01-28', V{enrollment_date}) = ", data: "d2:monthsBetween( '2020-01-28', V{enrollment_date})", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'AFkfzcDf4Fs', displayContent: "d2:inOrgUnitGroup('CHC') = ", data: "d2:inOrgUnitGroup('CHC')", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'wmAQnxbs7V8', displayContent: 'd2:round( 12.5 ) = ', data: 'd2:round( 12.5 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'tFGwyDBQk3b', displayContent: 'd2:round( 0 ) = ', data: 'd2:round( 0 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'NSQV537qvyu', displayContent: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = ", data: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking')", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'M7vYMD5uNwD', displayContent: 'd2:ceil(11.3) = ', data: 'd2:ceil(11.3)', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'cgdUEJkqq0J', displayContent: "d2:yearsBetween( '2010-01-28', V{enrollment_date}) = ", data: "d2:yearsBetween( '2010-01-28', V{enrollment_date})", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'xZpYbFPXWG2', displayContent: 'd2:zing( 1000 ) = ', data: 'd2:zing( 1000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'IGpzruAKVzk', displayContent: "d2:split('these-are-testing-values', '-', 2) = ", data: "d2:split('these-are-testing-values', '-', 2)", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'NLsawa3P5hc', displayContent: "d2:substring('hello dhis 2', 6, 10) = ", data: "d2:substring('hello dhis 2', 6, 10)", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'i0OgulFyVPQ', displayContent: 'd2:oizp( -10000000 ) = ', data: 'd2:oizp( -10000000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'PqzKFmEMmuz', displayContent: "d2:right('dhis', 3) = ", data: "d2:right('dhis', 3)", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'xIUDr1lRV6N', displayContent: "d2:addDays( '2018-04-20', 100 ) = ", data: "d2:addDays( '2018-04-20', 100 )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'RXmprywJ0Rb', displayContent: 'd2:floor( 11.5 ) = ', data: 'd2:floor( 11.5 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'cZQngI2IC1a', displayContent: "d2:length( 'dhis2 rocks' ) = ", data: "d2:length( 'dhis2 rocks' )", location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'qSe8GmlwpgZ', displayContent: "d2:weeksBetween('2020-01-28', V{enrollment_date} ) = ", data: "d2:weeksBetween('2020-01-28', V{enrollment_date} )", location: 'feedback', programRuleActionType: 'DISPLAYKEYVALUEPAIR' }, - { id: 'Tx4gHcLselM', displayContent: 'd2:oizp( 10000000 ) = ', data: 'd2:oizp( 10000000 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'f3MrrcCf1z2', displayContent: 'd2:modulus( 12 , 100 ) = ', data: 'd2:modulus( 12 , 100 )', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'Eeb7Ixr4Pv6', displayContent: 'd2:floor((5+5) / 2) = ', data: 'd2:floor((5+5) / 2)', location: 'feedback', programRuleActionType: 'DISPLAYTEXT' }, - { id: 'nKNmayYigcy', programStageId: 'PUZaKR0Jh2k', programRuleActionType: 'HIDEPROGRAMSTAGE' }, - ], - }]; - const programRulesVariables = []; + const trackedEntityAttributes = { + w75KJ2mc4zz: { id: 'w75KJ2mc4zz', valueType: 'TEXT' }, + zDhUuAYrxNC: { id: 'zDhUuAYrxNC', valueType: 'TEXT' }, + cejWyOfXge6: { id: 'cejWyOfXge6', valueType: 'TEXT', optionSetId: 'pC3N9N77UmT' }, + lZGmxYbs97q: { id: 'lZGmxYbs97q', valueType: 'NUMBER' }, + Z5z8vFQy0w0: { id: 'Z5z8vFQy0w0', valueType: 'URL' }, + TzqawmlPkI5: { id: 'TzqawmlPkI5', valueType: 'AGE' }, + f8j4XDEozvj: { id: 'f8j4XDEozvj', valueType: 'FILE_RESOURCE' }, + jBBkFuPKctq: { id: 'jBBkFuPKctq', valueType: 'ORGANISATION_UNIT' }, + A4Fg6jgWauf: { id: 'A4Fg6jgWauf', valueType: 'IMAGE' }, + CUbZcLm9LyN: { id: 'CUbZcLm9LyN', valueType: 'USERNAME' }, + p8htbyJHydl: { id: 'p8htbyJHydl', valueType: 'COORDINATE' }, + }; + const programRules = [ + { + id: 'g82J3xsNer9', + condition: 'true', + displayName: 'Testing the functions!', + programId: 'IpHINAT79UW', + programRuleActions: [ + { + id: 'Eeb7Ixr4Pvx', + displayContent: "d2:left('dhis', 3) = ", + data: "d2:left('dhis', 3)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'lbIGJYVI57u', + displayContent: 'd2:zing( -2 ) = ', + data: 'd2:zing( -2 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'kwKhYpVRDyj', + displayContent: "d2:monthsBetween( '2020-01-28', V{enrollment_date}) = ", + data: "d2:monthsBetween( '2020-01-28', V{enrollment_date})", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'polhYpVRDyj', + displayContent: "d2:daysBetween( '2020-01-28', V{enrollment_date}) = ", + data: "d2:daysBetween( '2020-01-28', V{enrollment_date})", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FkeGdlkYAVr', + displayContent: "d2:validatePattern('d2:daysBetween( '2020-01-28', V{enrollment_date})', 108)", + data: "d2:validatePattern(d2:daysBetween( '2020-01-28', V{enrollment_date}), 108)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'Foc3PhzoAVr', + displayContent: 'd2:count(#{undefinedVariable}) = ', + data: 'd2:count(#{unknow})', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FjkwPhzoAVr', + displayContent: "d2:countIfValue(#{undefinedVariable}, 'Male') = ", + data: "d2:countIfValue(#{undefinedVariable}, 'Male') = ", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'TkgrHcLselM', + displayContent: 'd2:countIfZeroPos(100) = ', + data: 'd2:countIfZeroPos(100)', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'Foc3PhzoAVr', + displayContent: 'd2:hasValue(#{undefinedVariable})', + data: 'd2:hasValue(#{undefinedVariable})', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FoljdkeoAVr', + displayContent: "d2:validatePattern('Male', 'a')", + data: "d2:validatePattern('Male','a')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FoljdlkYAVr', + displayContent: "d2:validatePattern('Male', 'Male')", + data: "d2:validatePattern('Male','Male')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'kpljdlkYAVr', + displayContent: 'd2:validatePattern()', + data: 'd2:validatePattern()', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FoljdjkRAVr', + displayContent: "d2:hasUserRole('admin')", + data: "d2:hasUserRole('admin')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FoljdkLRAVr', + displayContent: "d2:extractDataMatrixValue('batch number', 3)", + data: "d2:extractDataMatrixValue('batch number', 3)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FollkyLRAVr', + displayContent: "d2:extractDataMatrixValue('batch number', 'unknow')", + data: "d2:extractDataMatrixValue('batch number', 'unknow')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'lkEUdkLRAVr', + displayContent: "d2:extractDataMatrixValue('gtin', ']d2')", + data: "d2:extractDataMatrixValue('gtin', ']d2')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FlkodkLRAVr', + displayContent: "d2:extractDataMatrixValue('batch number', ']d2')", + data: "d2:extractDataMatrixValue('batch number', ']d2')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'kuYodkLRAVr', + displayContent: "d2:extractDataMatrixValue('production date', ']Q3unknown')", + data: "d2:extractDataMatrixValue('production date', ']Q3unknown')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'kuYookLRAVr', + displayContent: "d2:extractDataMatrixValue('lot number', ']Q3703')", + data: "d2:extractDataMatrixValue('lot number', ']Q3703')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'lkyodkLRAVr', + displayContent: "d2:extractDataMatrixValue('best before date', ']Q3369')", + data: "d2:extractDataMatrixValue('best before date', ']Q3369')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'lkpyodkLRAVr', + displayContent: "d2:extractDataMatrixValue('expiration date', ']Q3369')", + data: "d2:extractDataMatrixValue('expiration date', ']Q3369')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'lkyohgyRAVr', + displayContent: "d2:extractDataMatrixValue('serial number', ']Q3369')", + data: "d2:extractDataMatrixValue('serial number', ']Q3369')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'lkyolktRAVr', + displayContent: "d2:extractDataMatrixValue('unknow key', ']d2')", + data: "d2:extractDataMatrixValue('unknow key', ']d2')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FolpqkLRAVr', + displayContent: 'd2:lastEventDate(V{event_id})', + data: 'd2:lastEventDate(V{event_id})', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FolkokLRAVr', + displayContent: 'd2:lastEventDate(V{enrollment_date})', + data: 'd2:lastEventDate(V{enrollment_date})', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FolkwkLRAVr', + displayContent: 'd2:lastEventDate(#{undefinedVariable})', + data: 'd2:lastEventDate(#{undefinedVariable})', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'llokowfRAVr', + displayContent: "d2:addControlDigits('2')", + data: "d2:addControlDigits('2')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'lloksfegwAVr', + displayContent: "d2:addControlDigits('7')", + data: "d2:addControlDigits('7')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'lkyksfegwAVr', + displayContent: "d2:addControlDigits('9')", + data: "d2:addControlDigits('9')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'llolkyfRAVr', + displayContent: "d2:addControlDigits('12345678912')", + data: "d2:addControlDigits('12345678912')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'FollowfRAVr', + displayContent: 'd2:checkControlDigits(1)', + data: 'd2:checkControlDigits(1)', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'AFkfzcDf4Fs', + displayContent: "d2:inOrgUnitGroup('CHC') = ", + data: "d2:inOrgUnitGroup('CHC')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'wmAQnxbs7V8', + displayContent: 'd2:round( 12.5, 1 ) = ', + data: 'd2:round( 12.5, 1 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'tFGwyDBQk3b', + displayContent: 'd2:round( 0 ) = ', + data: 'd2:round( 0 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'NSQV537qvyu', + displayContent: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = ", + data: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking')", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'M7vYMD5uNwD', + displayContent: 'd2:ceil(11.3) = ', + data: 'd2:ceil(11.3)', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'cgdUEJkqq0J', + displayContent: "d2:yearsBetween( '2010-01-28', V{enrollment_date}) = ", + data: "d2:yearsBetween( '2010-01-28', V{enrollment_date})", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'xZpYbFPXWG2', + displayContent: 'd2:zing( 1000 ) = ', + data: 'd2:zing( 1000 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'IGpzruAKVzk', + displayContent: "d2:split('these-are-testing-values', '-', 2) = ", + data: "d2:split('these-are-testing-values', '-', 2)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'NLsawa3P5hc', + displayContent: "d2:substring('hello dhis 2', -1, 10) = ", + data: "d2:substring('hello dhis 2', -1, 10)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'i0OgulFyVPQ', + displayContent: 'd2:oizp( -10000000 ) = ', + data: 'd2:oizp( -10000000 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'PqzKFmEMmuz', + displayContent: "d2:right('dhis', 3) = ", + data: "d2:right('dhis', 3)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'xIUDr1lRV6N', + displayContent: "d2:addDays( '2018-04-20', 100 ) = ", + data: "d2:addDays( '2018-04-20', 100 )", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'RXmprywJ0Rb', + displayContent: 'd2:floor( 11.5 ) = ', + data: 'd2:floor( 11.5 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'cZQngI2IC1a', + displayContent: "d2:length( 'dhis2 rocks' ) = ", + data: "d2:length( 'dhis2 rocks' )", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'qSe8GmlwpgZ', + displayContent: "d2:weeksBetween('2020-01-28', V{enrollment_date} ) = ", + data: "d2:weeksBetween('2020-01-28', V{enrollment_date} )", + location: 'feedback', + programRuleActionType: 'DISPLAYKEYVALUEPAIR', + }, + { + id: 'Tx4gHcLselM', + displayContent: 'd2:oizp( 10000000 ) = ', + data: 'd2:oizp( 10000000 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'f3MrrcCf1z2', + displayContent: 'd2:modulus( 12 , 100 ) = ', + data: 'd2:modulus( 12 , 100 )', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'Eeb7Ixr4Pv6', + displayContent: 'd2:floor((5+5) / 2) = ', + data: 'd2:floor((5+5) / 2)', + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { id: 'nKNmayYigcy', programStageId: 'PUZaKR0Jh2k', programRuleActionType: 'HIDEPROGRAMSTAGE' }, + { + id: 'nKNmayYigcy', + programStageSectionId: 'SWfdBhglX0fk', + programRuleActionType: 'HIDESECTION', + }, + { + id: 'lJOYxhjupxz', + data: 'true', + trackedEntityAttributeId: 'w75KJ2mc4zz', + programRuleActionType: 'ASSIGN', + }, + { + id: 'lJOdxhjupxz', + data: 'true', + trackedEntityAttributeId: 'w75KJ2mc4zz', + programRuleActionType: 'ERRORONCOMPLETE', + }, + { + id: 'ljlYxhjupxz', + data: 'true', + trackedEntityAttributeId: 'w75KJ2mc4zz', + programRuleActionType: 'WARNINGONCOMPLETE', + }, + { + id: 'lljoxhjupxz', + data: 'true', + trackedEntityAttributeId: 'w75KJ2mc4zz', + programRuleActionType: 'SETMANDATORYFIELD', + }, + { + id: 'lgjoxhjupxz', + data: 'true', + optionGroupId: 'w75KJ2mc4zz', + programRuleActionType: 'HIDEOPTIONGROUP', + }, + { + id: 'lljljhjupxz', + data: 'true', + optionGroupId: 'w75KJ2mc4zz', + programRuleActionType: 'SHOWOPTIONGROUP', + }, + { id: 'hwgyO59SSxu', trackedEntityAttributeId: 'zDhUuAYrxNC', programRuleActionType: 'HIDEFIELD' }, + { id: 'khygyO59Sxu', trackedEntityAttributeId: 'unknown', programRuleActionType: 'HIDEFIELD' }, + { id: 'khtgyO5SSxu', trackedEntityAttributeId: 'Z5z8vFQy0w0', programRuleActionType: 'HIDEFIELD' }, + { id: 'hwgyOgy4Sxu', trackedEntityAttributeId: 'TzqawmlPkI5', programRuleActionType: 'HIDEFIELD' }, + { id: 'hwgyloeSSxu', trackedEntityAttributeId: 'f8j4XDEozvj', programRuleActionType: 'HIDEFIELD' }, + { id: 'lkoeO59SSxu', trackedEntityAttributeId: 'jBBkFuPKctq', programRuleActionType: 'HIDEFIELD' }, + { id: 'poe4O59SSxu', trackedEntityAttributeId: 'A4Fg6jgWauf', programRuleActionType: 'HIDEFIELD' }, + { id: 'gtyyO59SSxu', trackedEntityAttributeId: 'CUbZcLm9LyN', programRuleActionType: 'HIDEFIELD' }, + { id: 'kopyO59SSxu', trackedEntityAttributeId: 'p8htbyJHydl', programRuleActionType: 'HIDEFIELD' }, + { id: 'dsfsdfsw4rh', dataElementId: 'unknown', programRuleActionType: 'HIDEFIELD' }, + { + id: 'khy8GmlwpgZ', + displayContent: "d2:weeksBetween('2020-01-28', V{unknown} ) = ", + data: "d2:weeksBetween('2020-01-28', V{unknown} )", + location: 'feedback', + programRuleActionType: 'DISPLAYKEYVALUEPAIR', + }, + ], + }, + ]; + const programRuleVariables = [ + { + id: 'DoRHHfNPccb', + trackedEntityAttributeId: 'w75KJ2mc4zz', + displayName: 'INFECTION_SOURCE', + programId: 'IpHINAT79UW', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: false, + }, + { + id: 'lokHHfNPccb', + trackedEntityAttributeId: 'w75KJ2mc4zz', + displayName: 'INFECTION_SOURCE', + programId: 'IpHINAT79UW', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: false, + }, + { + id: 'Zj7UnCAulEk', + displayName: 'Zj7UnCAulEk', + programRuleVariableSourceType: variableSourceTypes.TEI_ATTRIBUTE, + trackedEntityAttributeId: 'w75KJ2mc4zz', + programId: 'IpHINAT79UW', + }, + ]; const optionSets = {}; - const teiValues = {}; + const teiValues = { + zDhUuAYrxNC: 'value', + Z5z8vFQy0w0: 'https://www.google.com/', + TzqawmlPkI5: '30', + f8j4XDEozvj: 'FILE_RESOURCE', + jBBkFuPKctq: 'ORGANISATION_UNIT', + A4Fg6jgWauf: 'IMAGE', + CUbZcLm9LyN: 'USERNAME', + p8htbyJHydl: { latitude: '12.4353', longitude: '67.34534' }, + }; const orgUnit = { id: 'DiszpKrYNg8', name: 'Ngelehun CHC' }; - const enrollmentData = { enrolledAt: '2020-05-14T22:00:00.000Z' }; + const enrollmentData = { enrolledAt: '2020-05-14T10:00:00.000Z' }; + const currentEvent = { + occurredAt: '2020-07-14T10:00:00.000Z', + da1Id: 'currentEventText', + dueDate: '2021-05-31T09:51:38.134', + enrollmentId: 'vVtmDlsu3me', + enrollmentStatus: 'ACTIVE', + eventDate: '2021-05-31T00:00:00.000', + eventId: 'BxGzDJK3JqN', + orgUnitId: 'DiszpKrYNg8', + orgUnitName: 'Ngelehun CHC', + programId: 'IpHINAT79UW', + programStageId: 'A03MvHHogjR', + status: 'ACTIVE', + trackedEntityInstanceId: 'vCGpQAWG17I', + }; // when const rulesEffects = rulesEngine.getProgramRuleEffects({ - programRulesContainer: { programRulesVariables, programRules, constants }, + programRulesContainer: { programRuleVariables, programRules, constants }, trackedEntityAttributes, selectedEntity: teiValues, selectedEnrollment: enrollmentData, selectedOrgUnit: orgUnit, optionSets, + currentEvent, }); // then expect(rulesEffects).toEqual([ - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Eeb7Ixr4Pvx', message: "d2:left('dhis', 3) = dhi" } }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Eeb7Ixr4Pvx', message: "d2:left('dhis', 3) = dhi" }, + }, { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'lbIGJYVI57u', message: 'd2:zing( -2 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'kwKhYpVRDyj', message: "d2:monthsBetween( '2020-01-28', V{enrollment_date}) = 3" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'AFkfzcDf4Fs', message: "d2:inOrgUnitGroup('CHC') = " } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'wmAQnxbs7V8', message: 'd2:round( 12.5 ) = 13' } }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'kwKhYpVRDyj', message: "d2:monthsBetween( '2020-01-28', V{enrollment_date}) = 3" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'polhYpVRDyj', message: "d2:daysBetween( '2020-01-28', V{enrollment_date}) = 107" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'FkeGdlkYAVr', + message: "d2:validatePattern('d2:daysBetween( '2020-01-28', V{enrollment_date})', 108) ", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Foc3PhzoAVr', message: 'd2:count(#{undefinedVariable}) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'FjkwPhzoAVr', message: "d2:countIfValue(#{undefinedVariable}, 'Male') = " }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'TkgrHcLselM', message: 'd2:countIfZeroPos(100) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Foc3PhzoAVr', message: 'd2:hasValue(#{undefinedVariable}) ' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'FoljdkeoAVr', message: "d2:validatePattern('Male', 'a') " }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'FoljdlkYAVr', message: "d2:validatePattern('Male', 'Male') true" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'kpljdlkYAVr', message: 'd2:validatePattern() ' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'FoljdjkRAVr', message: "d2:hasUserRole('admin') " }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'FoljdkLRAVr', + message: "d2:extractDataMatrixValue('batch number', 3) Incomplete DataMatrix input", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'FollkyLRAVr', + message: + "d2:extractDataMatrixValue('batch number', 'unknow') Unsupported GS1 identifier: {gs1Identifier}", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'lkEUdkLRAVr', + message: "d2:extractDataMatrixValue('gtin', ']d2') ", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'FlkodkLRAVr', + message: "d2:extractDataMatrixValue('batch number', ']d2') ", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'kuYodkLRAVr', + message: "d2:extractDataMatrixValue('production date', ']Q3unknown') ", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'kuYookLRAVr', + message: "d2:extractDataMatrixValue('lot number', ']Q3703') ", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'lkyodkLRAVr', + message: "d2:extractDataMatrixValue('best before date', ']Q3369') ", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'lkpyodkLRAVr', + message: "d2:extractDataMatrixValue('expiration date', ']Q3369') ", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'lkyohgyRAVr', + message: "d2:extractDataMatrixValue('serial number', ']Q3369') ", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'lkyolktRAVr', + message: "d2:extractDataMatrixValue('unknow key', ']d2') ", + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'FolpqkLRAVr', message: 'd2:lastEventDate(V{event_id}) 2020-07-14' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'FolkokLRAVr', message: 'd2:lastEventDate(V{enrollment_date}) ' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'FolkwkLRAVr', message: 'd2:lastEventDate(#{undefinedVariable}) ' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'llokowfRAVr', message: "d2:addControlDigits('2') 261" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'lloksfegwAVr', message: "d2:addControlDigits('7') 709" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'lkyksfegwAVr', message: "d2:addControlDigits('9') 950" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'llolkyfRAVr', message: "d2:addControlDigits('12345678912') 1234567891200" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'FollowfRAVr', message: 'd2:checkControlDigits(1) 1' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'AFkfzcDf4Fs', message: "d2:inOrgUnitGroup('CHC') = " }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'wmAQnxbs7V8', message: 'd2:round( 12.5, 1 ) = 12.5' }, + }, { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'tFGwyDBQk3b', message: 'd2:round( 0 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'NSQV537qvyu', message: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = dhis2isrocking" } }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { + id: 'NSQV537qvyu', + message: "d2:concatenate( 'dh', 'is', 2, 'is', 'rocking') = dhis2isrocking", + }, + }, { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'M7vYMD5uNwD', message: 'd2:ceil(11.3) = 12' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'cgdUEJkqq0J', message: "d2:yearsBetween( '2010-01-28', V{enrollment_date}) = 10" } }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'cgdUEJkqq0J', message: "d2:yearsBetween( '2010-01-28', V{enrollment_date}) = 10" }, + }, { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'xZpYbFPXWG2', message: 'd2:zing( 1000 ) = 1000' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'IGpzruAKVzk', message: "d2:split('these-are-testing-values', '-', 2) = testing" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'NLsawa3P5hc', message: "d2:substring('hello dhis 2', 6, 10) = dhis" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'i0OgulFyVPQ', message: 'd2:oizp( -10000000 ) = 0' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'PqzKFmEMmuz', message: "d2:right('dhis', 3) = his" } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'xIUDr1lRV6N', message: "d2:addDays( '2018-04-20', 100 ) = 2018-07-29" } }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'IGpzruAKVzk', message: "d2:split('these-are-testing-values', '-', 2) = testing" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'NLsawa3P5hc', message: "d2:substring('hello dhis 2', -1, 10) = " }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'i0OgulFyVPQ', message: 'd2:oizp( -10000000 ) = 0' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'PqzKFmEMmuz', message: "d2:right('dhis', 3) = his" }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'xIUDr1lRV6N', message: "d2:addDays( '2018-04-20', 100 ) = 2018-07-29" }, + }, { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'RXmprywJ0Rb', message: 'd2:floor( 11.5 ) = 11' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'cZQngI2IC1a', message: "d2:length( 'dhis2 rocks' ) = 11" } }, - { type: 'DISPLAYKEYVALUEPAIR', id: 'feedback', displayKeyValuePair: { id: 'qSe8GmlwpgZ', key: "d2:weeksBetween('2020-01-28', V{enrollment_date} ) = ", value: '15' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Tx4gHcLselM', message: 'd2:oizp( 10000000 ) = 1' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'f3MrrcCf1z2', message: 'd2:modulus( 12 , 100 ) = 12' } }, - { type: 'DISPLAYTEXT', id: 'feedback', displayText: { id: 'Eeb7Ixr4Pv6', message: 'd2:floor((5+5) / 2) = 5' } }, // check double parentheses + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'cZQngI2IC1a', message: "d2:length( 'dhis2 rocks' ) = 11" }, + }, + { + type: 'DISPLAYKEYVALUEPAIR', + id: 'feedback', + displayKeyValuePair: { + id: 'qSe8GmlwpgZ', + key: "d2:weeksBetween('2020-01-28', V{enrollment_date} ) = ", + value: '15', + }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Tx4gHcLselM', message: 'd2:oizp( 10000000 ) = 1' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'f3MrrcCf1z2', message: 'd2:modulus( 12 , 100 ) = 12' }, + }, + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Eeb7Ixr4Pv6', message: 'd2:floor((5+5) / 2) = 5' }, + }, { type: 'HIDEPROGRAMSTAGE', id: 'PUZaKR0Jh2k' }, + { id: 'SWfdBhglX0fk', type: 'HIDESECTION' }, + { id: 'w75KJ2mc4zz', targetDataType: 'trackedEntityAttribute', type: 'ASSIGN', value: 'true' }, + { + id: 'w75KJ2mc4zz', + message: ' true', + targetDataType: 'trackedEntityAttribute', + type: 'ERRORONCOMPLETE', + }, + { + id: 'w75KJ2mc4zz', + message: ' true', + targetDataType: 'trackedEntityAttribute', + type: 'WARNINGONCOMPLETE', + }, + { + id: 'w75KJ2mc4zz', + targetDataType: 'trackedEntityAttribute', + type: 'SETMANDATORYFIELD', + }, + { + content: undefined, + id: 'zDhUuAYrxNC', + targetDataType: 'trackedEntityAttribute', + type: 'HIDEFIELD', + hadValue: true, + name: undefined, + }, + { + content: undefined, + id: 'unknown', + targetDataType: 'trackedEntityAttribute', + type: 'HIDEFIELD', + }, + { + content: undefined, + id: 'Z5z8vFQy0w0', + targetDataType: 'trackedEntityAttribute', + type: 'HIDEFIELD', + hadValue: true, + name: undefined, + }, + { + content: undefined, + id: 'TzqawmlPkI5', + targetDataType: 'trackedEntityAttribute', + type: 'HIDEFIELD', + hadValue: true, + name: undefined, + }, + { + content: undefined, + id: 'f8j4XDEozvj', + targetDataType: 'trackedEntityAttribute', + type: 'HIDEFIELD', + }, + { + content: undefined, + id: 'jBBkFuPKctq', + targetDataType: 'trackedEntityAttribute', + type: 'HIDEFIELD', + }, + { + content: undefined, + id: 'A4Fg6jgWauf', + targetDataType: 'trackedEntityAttribute', + type: 'HIDEFIELD', + }, + { + content: undefined, + id: 'CUbZcLm9LyN', + targetDataType: 'trackedEntityAttribute', + type: 'HIDEFIELD', + hadValue: true, + name: undefined, + }, + { + content: undefined, + id: 'p8htbyJHydl', + targetDataType: 'trackedEntityAttribute', + type: 'HIDEFIELD', + hadValue: true, + name: undefined, + }, + { + content: undefined, + id: 'unknown', + targetDataType: 'dataElement', + type: 'HIDEFIELD', + }, + { + displayKeyValuePair: { + id: 'khy8GmlwpgZ', + key: "d2:weeksBetween('2020-01-28', V{unknown} ) = ", + value: '', + }, + id: 'feedback', + type: 'DISPLAYKEYVALUEPAIR', + }, ]); }); diff --git a/src/core_modules/capture-core/rules/__tests__/rulesEngine.test.js b/src/core_modules/capture-core/rules/__tests__/rulesEngine.test.js new file mode 100644 index 0000000000..4a0f04e813 --- /dev/null +++ b/src/core_modules/capture-core/rules/__tests__/rulesEngine.test.js @@ -0,0 +1,717 @@ +import { variableSourceTypes } from '@dhis2/rules-engine-javascript'; +import { rulesEngine } from '../rulesEngine'; + +describe('Rules engine', () => { + const constants = []; + const dataElementsInProgram = {}; + const programRuleVariables = []; + const orgUnit = { id: 'DiszpKrYNg8', name: 'Ngelehun CHC' }; + const optionSets = {}; + const currentEvent = {}; + + test('Rules engine without programRules', () => { + // when + const programRules = undefined; + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + currentEvent, + dataElements: dataElementsInProgram, + selectedOrgUnit: orgUnit, + optionSets, + }); + + // then + expect(rulesEffects).toEqual([]); + }); + + test('Program rule without an condition', () => { + // when + const programRules = [ + { + id: 'GC4gpdoSD4r', + condition: undefined, + description: 'Show warning if hemoglobin is dangerously low', + displayName: 'Hemoglobin warning', + programId: 'lxAQ7Zs9VYR', + programRuleActions: [ + { + id: 'suS9GnraCx1', + content: 'Hemoglobin value lower than normal', + displayContent: 'Hemoglobin value lower than normal', + dataElementId: 'vANAXwtLwcT', + programRuleActionType: 'SHOWWARNING', + }, + ], + }, + ]; + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + currentEvent, + dataElements: dataElementsInProgram, + selectedOrgUnit: orgUnit, + optionSets, + }); + + // then + expect(rulesEffects).toEqual([]); + }); + + test('Program rule condition error handeling', () => { + const programRules = [ + { + id: 'GC4gpdoSD4r', + condition: 'i am a condition with error', + description: 'Show warning if hemoglobin is dangerously low', + displayName: 'Hemoglobin warning', + programId: 'lxAQ7Zs9VYR', + programRuleActions: [ + { + id: 'suS9GnraCx1', + content: 'Hemoglobin value lower than normal', + displayContent: 'Hemoglobin value lower than normal', + dataElementId: 'vANAXwtLwcT', + programRuleActionType: 'SHOWWARNING', + }, + ], + }, + ]; + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + currentEvent, + dataElements: dataElementsInProgram, + selectedOrgUnit: orgUnit, + optionSets, + }); + + // then + expect(rulesEffects).toEqual([]); + }); + + test('user roles', () => { + rulesEngine.setSelectedUserRoles(['ADMIN']); + expect(rulesEngine.userRoles).toEqual(['ADMIN']); + }); + + test('SHOW_WARNING program rule effect with a general target', () => { + const programRules = [ + { + id: 'GC4gpdoSD4r', + condition: 'true', + description: 'Show warning if hemoglobin is dangerously low', + displayName: 'Hemoglobin warning', + programId: 'lxAQ7Zs9VYR', + programRuleActions: [ + { + id: 'SWfdB5lX0fk', + content: 'Hemoglobin value lower than normal', + displayContent: 'Hemoglobin value lower than normal', + programRuleActionType: 'SHOWWARNING', + }, + ], + }, + ]; + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + currentEvent, + dataElements: dataElementsInProgram, + selectedOrgUnit: orgUnit, + optionSets, + }); + + // then + expect(rulesEffects).toEqual([ + { + id: 'general', + type: 'SHOWWARNING', + warning: { + id: 'SWfdB5lX0fk', + message: 'Hemoglobin value lower than normal ', + }, + }, + ]); + }); + + test('SHOW_ERROR program rule effect with a general target', () => { + const programRules = [ + { + id: 'GC4gpdoSD4r', + condition: 'true', + description: 'Show error if hemoglobin is dangerously low', + displayName: 'Hemoglobin error', + programId: 'lxAQ7Zs9VYR', + programRuleActions: [ + { + id: 'SWfdB5lX0fk', + content: 'Hemoglobin value lower than normal', + displayContent: 'Hemoglobin value lower than normal', + programRuleActionType: 'SHOWERROR', + }, + ], + }, + ]; + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + currentEvent, + dataElements: dataElementsInProgram, + selectedOrgUnit: orgUnit, + optionSets, + }); + + // then + expect(rulesEffects).toEqual([ + { + id: 'general', + type: 'SHOWERROR', + error: { + id: 'SWfdB5lX0fk', + message: 'Hemoglobin value lower than normal ', + }, + }, + ]); + }); + + test('HIDE_PROGRAM_STAGE program rule effect corner case. The action does not have a program stage id', () => { + const programRules = [ + { + id: 'GC4gpdoSD4r', + condition: 'true', + description: 'Show warning if hemoglobin is dangerously low', + displayName: 'Hemoglobin warning', + programId: 'lxAQ7Zs9VYR', + programRuleActions: [ + { + id: 'nKNmayYigcy', + programRuleActionType: 'HIDEPROGRAMSTAGE', + }, + ], + }, + ]; + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + currentEvent, + dataElements: dataElementsInProgram, + selectedOrgUnit: orgUnit, + optionSets, + }); + + // then + expect(rulesEffects).toEqual([]); + }); + + test('HIDE_SECTION program rule effect corner case. The action does not have a program stage section id', () => { + const programRules = [ + { + id: 'GC4gpdoSD4r', + condition: 'true', + description: 'Show warning if hemoglobin is dangerously low', + displayName: 'Hemoglobin warning', + programId: 'lxAQ7Zs9VYR', + programRuleActions: [ + { + id: 'nKNmayYigcy', + programRuleActionType: 'HIDESECTION', + }, + ], + }, + ]; + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + currentEvent, + dataElements: dataElementsInProgram, + selectedOrgUnit: orgUnit, + optionSets, + }); + + // then + expect(rulesEffects).toEqual([]); + }); +}); + +describe('Program Rule Variables corner cases', () => { + const constants = []; + const orgUnit = { id: 'DiszpKrYNg8', name: 'Ngelehun CHC' }; + const optionSets = {}; + + test('without currentEvent and without otherEvents', () => { + // given + const programRules = [ + { + id: 'g82J3xsNer9', + condition: 'true', + displayName: 'Testing the variables source type', + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'Eeb7Ixr4Pvx', + displayContent: "d2:left('dhis', 3) = ", + data: "d2:left('dhis', 3)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'ElktIxr4Pvx', + displayContent: "d2:left('dhis', 3) = ", + data: "d2:left('dhis', 3)", + content: 'event_status', + programRuleActionType: 'ASSIGN', + }, + ], + }, + ]; + const dataElementsInProgram = { + f8j4XDEozvj: { id: 'f8j4XDEozvj', valueType: 'INTEGER', optionSetId: undefined }, + }; + const currentEvent = undefined; + const programRuleVariables = [ + { + id: 'DoRHHfNPccb', + dataElementId: 'f8j4XDEozvj', + displayName: 'INFECTION_SOURCE', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: false, + }, + { + id: 'lokHHfNPccb', + dataElementId: 'f8j4XDEozvj', + displayName: 'INFECTION_SOURCE', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_PREVIOUS_EVENT, + useNameForOptionSet: false, + }, + { + id: 'DolgHfNPccb', + dataElementId: 'f8j4XDEozvj', + displayName: 'INFECTION_SOURCE', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM, + useNameForOptionSet: false, + }, + ]; + + // when + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + selectedOrgUnit: orgUnit, + optionSets, + currentEvent, + dataElements: dataElementsInProgram, + }); + + // then + expect(rulesEffects).toEqual([ + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Eeb7Ixr4Pvx', message: "d2:left('dhis', 3) = dhi" }, + }, + ]); + }); + + test('without currentEvent and with otherEvents', () => { + // given + const programRules = [ + { + id: 'g82J3xsNer9', + condition: 'true', + displayName: 'Testing the variables source type', + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'Eeb7Ixr4Pvx', + displayContent: "d2:left('dhis', 3) = ", + data: "d2:left('dhis', 3)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'ElktIxr4Pvx', + displayContent: "d2:left('dhis', 3) = ", + data: "d2:left('dhis', 3)", + content: 'event_status', + programRuleActionType: 'ASSIGN', + }, + ], + }, + ]; + const dataElementsInProgram = { + f8j4XDEozvj: { id: 'f8j4XDEozvj', valueType: 'INTEGER', optionSetId: undefined }, + }; + const currentEvent = undefined; + const otherEvents = [ + { + da1Id: 'otherEventText', + dueDate: '2021-05-31T09:51:38.134', + enrollmentId: 'vVtmDlsu3me', + enrollmentStatus: 'ACTIVE', + eventDate: '2021-05-31T00:00:00.000', + eventId: 'BxGzDJK3JqN', + orgUnitId: 'DiszpKrYNg8', + orgUnitName: 'Ngelehun CHC', + programId: 'IpHINAT79UW', + programStageId: 'A03MvHHogjR', + status: 'ACTIVE', + trackedEntityInstanceId: 'vCGpQAWG17I', + occurredAt: '2021-05-31T00:00:00.000', + }, + ]; + const programRuleVariables = [ + { + id: 'lokHHfNPccb', + dataElementId: 'f8j4XDEozvj', + displayName: 'INFECTION_SOURCE', + programId: 'PNClHaZARtz', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_PREVIOUS_EVENT, + useNameForOptionSet: false, + }, + ]; + + // when + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + selectedOrgUnit: orgUnit, + optionSets, + currentEvent, + dataElements: dataElementsInProgram, + otherEvents, + }); + + // then + expect(rulesEffects).toEqual([ + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Eeb7Ixr4Pvx', message: "d2:left('dhis', 3) = dhi" }, + }, + ]); + }); + + test('with currentEvent and with otherEvents', () => { + // given + const programRules = [ + { + id: 'g82J3xsNer9', + condition: 'true', + displayName: 'Testing the variables source type', + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'Eeb7Ixr4Pvx', + displayContent: "d2:left('dhis', 3) = ", + data: "d2:left('dhis', 3)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'ElktIxr4Pvx', + displayContent: "d2:left('dhis', 3) = ", + data: "d2:left('dhis', 3)", + content: 'event_status', + programRuleActionType: 'ASSIGN', + }, + ], + }, + ]; + const dataElementsInProgram = { + f8j4XDEozvj: { id: 'f8j4XDEozvj', valueType: 'INTEGER', optionSetId: undefined }, + GieVkTxp4HH: { id: 'GieVkTxp4HH', valueType: 'NUMBER', optionSetId: undefined }, + }; + const currentEvent = { + occurredAt: '2020-07-14T22:00:00.000Z', + da1Id: 'currentEventText', + dueDate: '2021-05-31T09:51:38.134', + enrollmentId: 'vVtmDlsu3me', + enrollmentStatus: 'ACTIVE', + eventDate: '2021-05-31T00:00:00.000', + eventId: 'BlgrDJK3JqN', + orgUnitId: 'DiszpKrYNg8', + orgUnitName: 'Ngelehun CHC', + programId: 'IpHINAT79UW', + programStageId: 'A03MvHHogjR', + status: 'ACTIVE', + trackedEntityInstanceId: 'vCsfsAWG17I', + }; + const otherEvents = [ + { + da1Id: 'otherEventText', + dueDate: '2021-05-31T09:51:38.134', + enrollmentId: 'vVtmDlsu3me', + enrollmentStatus: 'ACTIVE', + eventDate: '2021-05-31T00:00:00.000', + eventId: 'BxGzDJK3JqN', + orgUnitId: 'DiszpKrYNg8', + orgUnitName: 'Ngelehun CHC', + programId: 'IpHINAT79UW', + programStageId: 'A03MvHHogjR', + status: 'ACTIVE', + trackedEntityInstanceId: 'vCGpQAWG17I', + occurredAt: '2021-05-31T00:00:00.000', + }, + ]; + const programRuleVariables = [ + { + id: 'lokHHfNPccb', + dataElementId: 'f8j4XDEozvj', + displayName: 'INFECTION_SOURCE', + programId: 'IpHINAT79UW', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_PREVIOUS_EVENT, + useNameForOptionSet: false, + }, + { + id: 'ZghUnCAulEk.GieVkTxp4HH', + displayName: 'ZghUnCAulEk.GieVkTxp4HH', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE, + programStageId: 'A03MvHHogjR', + dataElementId: 'GieVkTxp4HH', + programId: 'IpHINAT79UW', + }, + { + id: 'Zj7UnsdhlEk.GieVkTxp4HH', + displayName: 'Zj7UnsdhlEk.GieVkTxp4HH', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE, + dataElementId: 'GieVkTxp4HH', + programId: 'IpHINAT79UW', + }, + { + id: 'Zj7luCAulEk.GieVkTxp4HH', + displayName: 'Zj7luCAulEk.GieVkTxp4HH', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE, + programStageId: 'AsdfMvHHgjR', + dataElementId: 'GieVkTxp4HH', + programId: 'IpHINAT79UW', + }, + ]; + + // when + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + selectedOrgUnit: orgUnit, + optionSets, + currentEvent, + dataElements: dataElementsInProgram, + otherEvents, + }); + + // then + expect(rulesEffects).toEqual([ + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Eeb7Ixr4Pvx', message: "d2:left('dhis', 3) = dhi" }, + }, + ]); + }); + + test('currentEvent without occurredAt date', () => { + // given + const programRules = [ + { + id: 'g82J3xsNer9', + condition: 'true', + displayName: 'Testing the variables source type', + programId: 'PNClHaZARtz', + programRuleActions: [ + { + id: 'Eeb7Ixr4Pvx', + displayContent: "d2:left('dhis', 3) = ", + data: "d2:left('dhis', 3)", + location: 'feedback', + programRuleActionType: 'DISPLAYTEXT', + }, + { + id: 'ElktIxr4Pvx', + displayContent: "d2:left('dhis', 3) = ", + data: "d2:left('dhis', 3)", + content: 'event_status', + programRuleActionType: 'ASSIGN', + }, + ], + }, + ]; + const dataElementsInProgram = { + f8j4XDEozvj: { id: 'f8j4XDEozvj', valueType: 'INTEGER', optionSetId: undefined }, + GieVkTxp4HH: { id: 'GieVkTxp4HH', valueType: 'NUMBER', optionSetId: undefined }, + }; + const currentEvent = { + da1Id: 'currentEventText', + dueDate: '2021-05-31T09:51:38.134', + enrollmentId: 'vVtmDlsu3me', + enrollmentStatus: 'ACTIVE', + eventDate: '2021-05-31T00:00:00.000', + eventId: 'BlgrDJK3JqN', + orgUnitId: 'DiszpKrYNg8', + orgUnitName: 'Ngelehun CHC', + programId: 'IpHINAT79UW', + programStageId: 'A03MvHHogjR', + status: 'ACTIVE', + trackedEntityInstanceId: 'vCsfsAWG17I', + }; + const otherEvents = [ + { + da1Id: 'otherEventText', + dueDate: '2021-05-31T09:51:38.134', + enrollmentId: 'vVtmDlsu3me', + enrollmentStatus: 'ACTIVE', + eventDate: '2021-05-31T00:00:00.000', + eventId: 'BxGzDJK3JqN', + orgUnitId: 'DiszpKrYNg8', + orgUnitName: 'Ngelehun CHC', + programId: 'IpHINAT79UW', + programStageId: 'A03MvHHogjR', + status: 'ACTIVE', + trackedEntityInstanceId: 'vCGpQAWG17I', + occurredAt: '2021-05-31T00:00:00.000', + }, + ]; + const programRuleVariables = [ + { + id: 'lokHHfNPccb', + dataElementId: 'f8j4XDEozvj', + displayName: 'INFECTION_SOURCE', + programId: 'IpHINAT79UW', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_PREVIOUS_EVENT, + useNameForOptionSet: false, + }, + { + id: 'ZghUnCAulEk.GieVkTxp4HH', + displayName: 'ZghUnCAulEk.GieVkTxp4HH', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE, + programStageId: 'A03MvHHogjR', + dataElementId: 'GieVkTxp4HH', + programId: 'IpHINAT79UW', + }, + { + id: 'Zj7UnsdhlEk.GieVkTxp4HH', + displayName: 'Zj7UnsdhlEk.GieVkTxp4HH', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE, + dataElementId: 'GieVkTxp4HH', + programId: 'IpHINAT79UW', + }, + { + id: 'Zj7luCAulEk.GieVkTxp4HH', + displayName: 'Zj7luCAulEk.GieVkTxp4HH', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE, + programStageId: 'AsdfMvHHgjR', + dataElementId: 'GieVkTxp4HH', + programId: 'IpHINAT79UW', + }, + ]; + + // when + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + selectedOrgUnit: orgUnit, + optionSets, + currentEvent, + dataElements: dataElementsInProgram, + otherEvents, + }); + + // then + expect(rulesEffects).toEqual([ + { + type: 'DISPLAYTEXT', + id: 'feedback', + displayText: { id: 'Eeb7Ixr4Pvx', message: "d2:left('dhis', 3) = dhi" }, + }, + ]); + }); + + test('programRuleVariable with a value type not supported', () => { + // given + const trackedEntityAttributes = { + w75KJ2mc4zz: { id: 'w75KJ2mc4zz', valueType: 'UNKNOWN' }, + }; + const programRules = []; + const currentEvent = {}; + const programRuleVariables = [ + { + id: 'DoRHHfNPccb', + displayName: 'INFECTION_SOURCE', + trackedEntityAttributeId: 'w75KJ2mc4zz', + programId: 'IpHINAT79UW', + programRuleVariableSourceType: variableSourceTypes.TEI_ATTRIBUTE, + useNameForOptionSet: false, + }, + ]; + + // when + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + selectedOrgUnit: orgUnit, + optionSets, + currentEvent, + trackedEntityAttributes, + }); + + // then + expect(rulesEffects).toEqual([]); + }); + + test('HIDEFIELD effect when the form values are empty', () => { + // given + const programRules = [ + { + id: 'g82J3xsNer9', + condition: 'true', + displayName: 'Testing the variables source type', + programId: 'PNClHaZARtz', + programRuleActions: [ + { id: 'hwgyO59SSxu', trackedEntityAttributeId: 'zDhUuAYrxNC', programRuleActionType: 'HIDEFIELD' }, + ], + }, + ]; + const trackedEntityAttributes = { + zDhUuAYrxNC: { id: 'zDhUuAYrxNC', valueType: 'TEXT' }, + }; + const programRuleVariables = [ + { + id: 'DoRHHfNPccb', + trackedEntityAttributeId: 'w75KJ2mc4zz', + displayName: 'INFECTION_SOURCE', + programId: 'IpHINAT79UW', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: false, + }, + { + id: 'lokHHfNPccb', + trackedEntityAttributeId: 'w75KJ2mc4zz', + displayName: 'INFECTION_SOURCE', + programId: 'IpHINAT79UW', + programRuleVariableSourceType: variableSourceTypes.DATAELEMENT_CURRENT_EVENT, + useNameForOptionSet: false, + }, + { + id: 'Zj7UnCAulEk', + displayName: 'Zj7UnCAulEk', + programRuleVariableSourceType: variableSourceTypes.TEI_ATTRIBUTE, + trackedEntityAttributeId: 'w75KJ2mc4zz', + programId: 'IpHINAT79UW', + }, + ]; + const teiValues = {}; + const enrollmentData = { enrolledAt: '2020-05-14T22:00:00.000Z' }; + const currentEvent = undefined; + + // when + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + trackedEntityAttributes, + selectedEntity: teiValues, + selectedEnrollment: enrollmentData, + selectedOrgUnit: orgUnit, + optionSets, + currentEvent, + }); + + // then + expect(rulesEffects).toEqual([ + { + content: undefined, + id: 'zDhUuAYrxNC', + targetDataType: 'trackedEntityAttribute', + type: 'HIDEFIELD', + }, + ]); + }); +}); From a13a766ea463514dfdd090b8d40db6406dac80bb Mon Sep 17 00:00:00 2001 From: eirikhaugstulen Date: Tue, 5 Dec 2023 13:00:13 +0100 Subject: [PATCH 13/32] fix: [DHIS2-15983] Enrollment date not assigned on form init (#3475) --- .../DataEntries/Enrollment/actions/open.actionBatchs.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core_modules/capture-core/components/DataEntries/Enrollment/actions/open.actionBatchs.js b/src/core_modules/capture-core/components/DataEntries/Enrollment/actions/open.actionBatchs.js index 2507d1c474..8e120d4beb 100644 --- a/src/core_modules/capture-core/components/DataEntries/Enrollment/actions/open.actionBatchs.js +++ b/src/core_modules/capture-core/components/DataEntries/Enrollment/actions/open.actionBatchs.js @@ -71,6 +71,7 @@ export const openDataEntryForNewEnrollmentBatchAsync = async ({ const formId = getDataEntryKey(dataEntryId, itemId); const addFormDataActions = addFormData(`${dataEntryId}-${itemId}`, formValues); const firstStageDataEntryPropsToInclude = firstStage && getDataEntryPropsToInclude(firstStage.stageForm); + const defaultDataEntryValues = { enrolledAt: convertDateObjectToDateFormatString(new Date()) }; const dataEntryPropsToInclude = [ ...enrollmentDataEntryPropsToInclude, ...extraDataEntryProps, @@ -88,7 +89,7 @@ export const openDataEntryForNewEnrollmentBatchAsync = async ({ dataEntryId, itemId, dataEntryPropsToInclude, - { enrolledAt: convertDateObjectToDateFormatString(new Date()) }, + defaultDataEntryValues, ); const effects = getApplicableRuleEffectsForTrackerProgram({ @@ -96,6 +97,7 @@ export const openDataEntryForNewEnrollmentBatchAsync = async ({ orgUnit, stage: firstStage, attributeValues: clientValues, + enrollmentData: defaultDataEntryValues, formFoundation, }); From c1dfbdb3352388bba7d51b8bc2b9d033d10967c3 Mon Sep 17 00:00:00 2001 From: eirikhaugstulen Date: Tue, 5 Dec 2023 13:13:44 +0100 Subject: [PATCH 14/32] fix: [DHIS2-15694] Cancel button in Relationship (#3471) --- .../NewEventThroughAddRelationship.feature | 5 +++++ .../NewEventThroughAddRelationship/index.js | 9 ++++++++ cypress/e2e/NewPage.feature | 7 +++++++ .../EnrollmentRegistrationEntry.component.js | 17 +++------------ .../EnrollmentRegistrationEntry.container.js | 2 ++ .../EnrollmentRegistrationEntry.types.js | 2 ++ ...ewEventNewRelationshipWrapper.component.js | 1 + .../SingleEventRegistrationEntry.container.js | 3 +-- .../SingleEventRegistrationEntry.types.js | 4 ++++ .../TeiRegistrationEntry.component.js | 18 +++------------- .../TeiRegistrationEntry.types.js | 1 + .../RegistrationDataEntry.component.js | 20 +++++++++++++++--- .../RegistrationDataEntry.types.js | 2 +- .../NewRelationship.component.js | 1 + .../DataEntryEnrollment.component.js | 2 ++ .../Enrollment/dataEntryEnrollment.types.js | 1 + ...ataEntryTrackedEntityInstance.component.js | 2 ++ .../dataEntryTrackedEntityInstance.types.js | 1 + .../RegisterTei/RegisterTei.component.js | 6 ++++-- .../RegisterTei/RegisterTei.container.js | 3 ++- .../RegisterTei/RegisterTei.types.js | 1 + .../TeiRelationship.component.js | 2 ++ ...ewEventNewRelationshipWrapper.component.js | 3 ++- .../DataEntryEnrollment.component.js | 2 ++ .../Enrollment/dataEntryEnrollment.types.js | 1 + .../DataEntryTrackedEntityInstance.js | 2 ++ .../dataEntryTrackedEntityInstance.types.js | 1 + .../RegisterTei/RegisterTei.component.js | 6 ++++-- .../RegisterTei/RegisterTei.container.js | 2 ++ .../RegisterTei/RegisterTei.types.js | 1 + ...kedEntityRelationshipsWrapper.component.js | 2 ++ .../NewTrackedEntityRelationship.component.js | 2 ++ .../NewTrackedEntityRelationship.types.js | 21 +++++++++++-------- .../WidgetTrackedEntityRelationship.types.js | 1 + 34 files changed, 104 insertions(+), 50 deletions(-) diff --git a/cypress/e2e/NewEventThroughAddRelationship.feature b/cypress/e2e/NewEventThroughAddRelationship.feature index 5276bbb960..f0db9f2503 100644 --- a/cypress/e2e/NewEventThroughAddRelationship.feature +++ b/cypress/e2e/NewEventThroughAddRelationship.feature @@ -23,3 +23,8 @@ Feature: User adds events And you submit the event form with the associated relationship to the already existing person Then the event and relationship should be sent to the server successfully + Scenario: User gets navigated correctly when clicking on the back button + Given you open the the new event page in Ngelehun and malaria case context + When you navigate to register a person relationship + And you click the cancel button + Then you should be navigated back to the event form diff --git a/cypress/e2e/NewEventThroughAddRelationship/index.js b/cypress/e2e/NewEventThroughAddRelationship/index.js index d525b595a4..3e17338b14 100644 --- a/cypress/e2e/NewEventThroughAddRelationship/index.js +++ b/cypress/e2e/NewEventThroughAddRelationship/index.js @@ -168,3 +168,12 @@ Then('the event and relationship should be sent to the server successfully', () }); }); }); + +When('you click the cancel button', () => { + cy.get('[data-test="cancel-button"]') + .click(); +}); + +Then('you should be navigated back to the event form', () => { + cy.contains('New Malaria case registration'); +}); diff --git a/cypress/e2e/NewPage.feature b/cypress/e2e/NewPage.feature index 220ca7e971..afbc13720c 100644 --- a/cypress/e2e/NewPage.feature +++ b/cypress/e2e/NewPage.feature @@ -94,6 +94,13 @@ Feature: User creates a new entries from the registration page Then you are navigated to the Antenatal care visit registration page Then program and organisation unit is still selected in top bar + Scenario: Clicking the cancel button should navigate with correct context + Given you are on the default registration page + And you select org unit + And you select Child Programme + When you click the cancel button + Then you are navigated to the working list with programId IpHINAT79UW + ### New event in Antenatal care visit Scenario: New event in Antenatal care visit > Submitting the form with empty visit date throws validation error diff --git a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.component.js b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.component.js index 97d9a7165c..78e63ddf59 100644 --- a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.component.js +++ b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.component.js @@ -4,7 +4,6 @@ import { Button, spacers } from '@dhis2/ui'; import i18n from '@dhis2/d2-i18n'; import { withStyles } from '@material-ui/core'; import { compose } from 'redux'; -import { useHistory } from 'react-router-dom'; import { useScopeInfo } from '../../../hooks/useScopeInfo'; import { scopeTypes } from '../../../metaData'; import { DiscardDialog } from '../../Dialogs/DiscardDialog.component'; @@ -14,7 +13,6 @@ import { withSaveHandler } from '../../DataEntry'; import { withLoadingIndicator } from '../../../HOC'; import { InfoIconText } from '../../InfoIconText'; import { withErrorMessagePostProcessor } from '../withErrorMessagePostProcessor'; -import { buildUrlQueryString } from '../../../utils/routing'; import { withDuplicateCheckOnSave } from '../common/TEIAndEnrollment/DuplicateCheckOnSave'; import { defaultDialogProps } from '../../Dialogs/DiscardDialog.constants'; @@ -52,6 +50,7 @@ const EnrollmentRegistrationEntryPlain = saveButtonText, classes, onSave, + onCancel, onPostProcessErrorMessage, orgUnitId, orgUnit, @@ -60,26 +59,16 @@ const EnrollmentRegistrationEntryPlain = isSavingInProgress, ...rest }: PlainProps) => { - const { push } = useHistory(); const [showWarning, setShowWarning] = useState(false); const { scopeType, trackedEntityName, programName } = useScopeInfo(selectedScopeId); const handleOnCancel = () => { if (!isUserInteractionInProgress) { - navigateToWorkingListsPage(); + onCancel(); } else { setShowWarning(true); } }; - const navigateToWorkingListsPage = () => { - const url = - scopeType === scopeTypes.TRACKER_PROGRAM - ? - buildUrlQueryString({ programId: selectedScopeId, orgUnitId }) - : - buildUrlQueryString({ orgUnitId }); - return push(`/?${url}`); - }; return ( <> @@ -130,7 +119,7 @@ const EnrollmentRegistrationEntryPlain = } { setShowWarning(false); }} /> diff --git a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.container.js b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.container.js index 2da9aba5b1..92ff9612b7 100644 --- a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.container.js +++ b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.container.js @@ -19,6 +19,7 @@ export const EnrollmentRegistrationEntry: ComponentType = ({ orgUnitId, teiId, onSave, + onCancel, ...passOnProps }) => { const { orgUnit, error } = useCoreOrgUnit(orgUnitId); @@ -68,6 +69,7 @@ export const EnrollmentRegistrationEntry: ComponentType = ({ formId={formId} formFoundation={formFoundation} id={id} + onCancel={onCancel} saveButtonText={saveButtonText(trackedEntityTypeNameLC)} ready={ready && !!enrollmentMetadata} teiId={teiId} diff --git a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.types.js b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.types.js index 3e4ea25e82..be426afafc 100644 --- a/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.types.js +++ b/src/core_modules/capture-core/components/DataEntries/EnrollmentRegistrationEntry/EnrollmentRegistrationEntry.types.js @@ -40,6 +40,7 @@ export type OwnProps = $ReadOnly<{| selectedScopeId: string, fieldOptions?: Object, onSave: SaveForDuplicateCheck, + onCancel: () => void, duplicatesReviewPageSize: number, renderDuplicatesCardActions?: RenderCustomCardActions, renderDuplicatesDialogActions?: (onCancel: () => void, onSave: SaveForDuplicateCheck) => Node, @@ -55,6 +56,7 @@ type ContainerProps = {| ready: boolean, orgUnitId: string, orgUnit: ?OrgUnit, + onCancel: () => void, isUserInteractionInProgress: boolean, isSavingInProgress: boolean, enrollmentMetadata: RegistrationFormMetadata, diff --git a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/NewRelationshipWrapper/NewEventNewRelationshipWrapper.component.js b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/NewRelationshipWrapper/NewEventNewRelationshipWrapper.component.js index 1151c1e4ae..d5d7ad6b4a 100644 --- a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/NewRelationshipWrapper/NewEventNewRelationshipWrapper.component.js +++ b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/NewRelationshipWrapper/NewEventNewRelationshipWrapper.component.js @@ -115,6 +115,7 @@ class NewEventNewRelationshipWrapper extends React.Component { diff --git a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/SingleEventRegistrationEntry.container.js b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/SingleEventRegistrationEntry.container.js index e32730dd2c..5aa066ac07 100644 --- a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/SingleEventRegistrationEntry.container.js +++ b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/SingleEventRegistrationEntry.container.js @@ -24,8 +24,7 @@ const makeMapStateToProps = (): MapStateToProps => { }); }; -const mapDispatchToProps = () => ({ -}); +const mapDispatchToProps = () => ({}); const mergeProps = (stateProps: StateProps): StateProps => (stateProps); diff --git a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/SingleEventRegistrationEntry.types.js b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/SingleEventRegistrationEntry.types.js index b9f2259497..50f64543ad 100644 --- a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/SingleEventRegistrationEntry.types.js +++ b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/SingleEventRegistrationEntry.types.js @@ -16,4 +16,8 @@ export type ContainerProps = {| id: string, |}; +export type DispatchProps = {| + onCancel: () => void, +|}; + export type MapStateToProps = (ReduxState, ContainerProps) => StateProps; diff --git a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.component.js b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.component.js index 3e2ea0d8a9..457fe3a112 100644 --- a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.component.js +++ b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.component.js @@ -4,7 +4,6 @@ import { compose } from 'redux'; import { Button, spacers } from '@dhis2/ui'; import i18n from '@dhis2/d2-i18n'; import { withStyles } from '@material-ui/core'; -import { useHistory } from 'react-router-dom'; import { useScopeInfo } from '../../../hooks/useScopeInfo'; import { scopeTypes } from '../../../metaData'; import { TrackedEntityInstanceDataEntry } from '../TrackedEntityInstance'; @@ -15,7 +14,6 @@ import { DiscardDialog } from '../../Dialogs/DiscardDialog.component'; import { withSaveHandler } from '../../DataEntry'; import { InfoIconText } from '../../InfoIconText'; import { withErrorMessagePostProcessor } from '../withErrorMessagePostProcessor'; -import { buildUrlQueryString } from '../../../utils/routing'; import { withDuplicateCheckOnSave } from '../common/TEIAndEnrollment/DuplicateCheckOnSave'; import { defaultDialogProps } from '../../Dialogs/DiscardDialog.constants'; import { useMetadataForRegistrationForm } from '../common/TEIAndEnrollment/useMetadataForRegistrationForm'; @@ -49,9 +47,9 @@ const TeiRegistrationEntryPlain = trackedEntityName, isUserInteractionInProgress, isSavingInProgress, + onCancel, ...rest }: PlainProps) => { - const { push } = useHistory(); const [showWarning, setShowWarning] = useState(false); const { scopeType } = useScopeInfo(selectedScopeId); const { formId, formFoundation } = useMetadataForRegistrationForm({ selectedScopeId }); @@ -60,22 +58,12 @@ const TeiRegistrationEntryPlain = const handleOnCancel = () => { if (!isUserInteractionInProgress) { - navigateToWorkingListsPage(); + onCancel(); } else { setShowWarning(true); } }; - const navigateToWorkingListsPage = () => { - const url = - scopeType === scopeTypes.TRACKER_PROGRAM - ? - buildUrlQueryString({ programId: selectedScopeId, orgUnitId }) - : - buildUrlQueryString({ orgUnitId }); - return push(`/?${url}`); - }; - return ( <> { @@ -120,7 +108,7 @@ const TeiRegistrationEntryPlain = { setShowWarning(false); }} /> diff --git a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js index 33f32eabf8..93062803b9 100644 --- a/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js +++ b/src/core_modules/capture-core/components/DataEntries/TeiRegistrationEntry/TeiRegistrationEntry.types.js @@ -15,6 +15,7 @@ export type OwnProps = $ReadOnly<{| saveButtonText: string, fieldOptions?: Object, onSave: (TeiPayload) => void, + onCancel: () => void, duplicatesReviewPageSize: number, isSavingInProgress?: boolean, inheritedAttributes?: Array, diff --git a/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.component.js b/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.component.js index af18875d9d..308671c147 100644 --- a/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.component.js +++ b/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.component.js @@ -1,6 +1,7 @@ // @flow import React, { type ComponentType, useContext, useCallback } from 'react'; import { useDispatch } from 'react-redux'; +import { useHistory } from 'react-router'; import i18n from '@dhis2/d2-i18n'; import { Button, colors, spacers } from '@dhis2/ui'; import { Grid, withStyles } from '@material-ui/core'; @@ -13,7 +14,7 @@ import { TrackedEntityTypeSelector } from '../../../TrackedEntityTypeSelector'; import { DataEntryWidgetOutput } from '../../../DataEntryWidgetOutput/DataEntryWidgetOutput.container'; import { ResultsPageSizeContext } from '../../shared-contexts'; import { navigateToEnrollmentOverview } from '../../../../actions/navigateToEnrollmentOverview/navigateToEnrollmentOverview.actions'; -import { useLocationQuery } from '../../../../utils/routing'; +import { buildUrlQueryString, useLocationQuery } from '../../../../utils/routing'; import { EnrollmentRegistrationEntryWrapper } from '../EnrollmentRegistrationEntryWrapper.component'; import { useCurrentOrgUnitId } from '../../../../hooks/useCurrentOrgUnitId'; @@ -94,18 +95,29 @@ const RegistrationDataEntryPlain = ({ teiId, trackedEntityInstanceAttributes, }: Props) => { + const { push } = useHistory(); const { resultsPageSize } = useContext(ResultsPageSizeContext); const { scopeType, programName, trackedEntityName } = useScopeInfo(selectedScopeId); const titleText = useScopeTitleText(selectedScopeId); const currentOrgUnitId = useCurrentOrgUnitId(); + const onCancel = useCallback(() => { + let url; + if (scopeType === scopeTypes.TRACKER_PROGRAM) { + url = buildUrlQueryString({ programId: selectedScopeId, orgUnitId: currentOrgUnitId }); + } else { + url = buildUrlQueryString({ orgUnitId: currentOrgUnitId }); + } + return push(`/?${url}`); + }, [currentOrgUnitId, push, scopeType, selectedScopeId]); + const handleRegistrationScopeSelection = (id) => { setScopeId(id); }; - const renderDuplicatesDialogActions = useCallback((onCancel, onSave) => ( + const renderDuplicatesDialogActions = useCallback((callbackOnCancel, onSave) => ( ), []); @@ -180,6 +192,7 @@ const RegistrationDataEntryPlain = ({ teiId={teiId} selectedScopeId={selectedScopeId} onSave={onSaveWithEnrollment} + onCancel={onCancel} saveButtonText={(trackedEntityTypeNameLC: string) => i18n.t('Save {{trackedEntityTypeName}}', { trackedEntityTypeName: trackedEntityTypeNameLC, interpolation: { escapeValue: false }, @@ -232,6 +245,7 @@ const RegistrationDataEntryPlain = ({ id={dataEntryId} selectedScopeId={selectedScopeId} orgUnitId={currentOrgUnitId} + onCancel={onCancel} saveButtonText={i18n.t('Save {{trackedEntityName}}', { trackedEntityName, interpolation: { escapeValue: false }, diff --git a/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js b/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js index 22e908fb66..41330409c8 100644 --- a/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js +++ b/src/core_modules/capture-core/components/Pages/New/RegistrationDataEntry/RegistrationDataEntry.types.js @@ -17,7 +17,7 @@ export type OwnProps = $ReadOnly<{| selectedScopeId: string, dataEntryId: string, teiId?: ?string, - trackedEntityInstanceAttributes?: Array + trackedEntityInstanceAttributes?: Array, |}>; type ContainerProps = {| diff --git a/src/core_modules/capture-core/components/Pages/NewRelationship/NewRelationship.component.js b/src/core_modules/capture-core/components/Pages/NewRelationship/NewRelationship.component.js index 1ebcfad048..6ff7297604 100644 --- a/src/core_modules/capture-core/components/Pages/NewRelationship/NewRelationship.component.js +++ b/src/core_modules/capture-core/components/Pages/NewRelationship/NewRelationship.component.js @@ -9,6 +9,7 @@ import { RelationshipNavigation } from './RelationshipNavigation/RelationshipNav type Props = { onAddRelationship: (relationshipType: { id: string, name: string }, entity: Object, entityType: string) => void, + onCancel: () => {}, classes: { container: string, }, diff --git a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js index 19d78a8c31..42dc5b3760 100644 --- a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js +++ b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js @@ -12,6 +12,7 @@ const NewEnrollmentRelationshipPlain = ({ theme, onSave, + onCancel, programId, duplicatesReviewPageSize, renderDuplicatesDialogActions, @@ -33,6 +34,7 @@ const NewEnrollmentRelationshipPlain = interpolation: { escapeValue: false }, })} onSave={onSave} + onCancel={onCancel} duplicatesReviewPageSize={duplicatesReviewPageSize} renderDuplicatesDialogActions={renderDuplicatesDialogActions} renderDuplicatesCardActions={renderDuplicatesCardActions} diff --git a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js index 452fdf271f..38612d6fda 100644 --- a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js +++ b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js @@ -12,6 +12,7 @@ export type Props = {| programId: string, enrollmentMetadata?: Enrollment, onSave: SaveForEnrollmentAndTeiRegistration, + onCancel: () => void, duplicatesReviewPageSize: number, renderDuplicatesCardActions?: RenderCustomCardActions, renderDuplicatesDialogActions?: (onCancel: () => void, onSave: SaveForEnrollmentAndTeiRegistration) => Node, diff --git a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.component.js b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.component.js index 2f04955d2a..baf4bd3e05 100644 --- a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.component.js +++ b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.component.js @@ -12,6 +12,7 @@ const RelationshipTrackedEntityInstancePlain = ({ theme, onSave, + onCancel, teiRegistrationMetadata = {}, duplicatesReviewPageSize, renderDuplicatesDialogActions, @@ -35,6 +36,7 @@ const RelationshipTrackedEntityInstancePlain = })} fieldOptions={fieldOptions} onSave={onSave} + onCancel={onCancel} duplicatesReviewPageSize={duplicatesReviewPageSize} renderDuplicatesDialogActions={renderDuplicatesDialogActions} renderDuplicatesCardActions={renderDuplicatesCardActions} diff --git a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js index 20f5463e75..0a49a28dc5 100644 --- a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js +++ b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js @@ -12,6 +12,7 @@ import type { export type Props = {| theme: Theme, onSave: (TeiPayload) => void, + onCancel: () => void, teiRegistrationMetadata?: TeiRegistration, duplicatesReviewPageSize: number, renderDuplicatesCardActions?: RenderCustomCardActions, diff --git a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/RegisterTei.component.js b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/RegisterTei.component.js index ee4e752c8e..6269d5ec2a 100644 --- a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/RegisterTei.component.js +++ b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/RegisterTei.component.js @@ -60,6 +60,7 @@ const RegisterTeiPlain = ({ itemId, onLink, onSave, + onCancel, onGetUnsavedAttributeValues, trackedEntityName, newRelationshipProgramId, @@ -75,9 +76,9 @@ const RegisterTeiPlain = ({ /> ), [onLink]); - const renderDuplicatesDialogActions = useCallback((onCancel, onSaveArgument) => ( + const renderDuplicatesDialogActions = useCallback((callbackOnCancel, onSaveArgument) => ( @@ -104,6 +105,7 @@ const RegisterTeiPlain = ({ }) => (programId || trackedEntityTypeId), ); -export const RegisterTei = ({ onLink, onSave, onGetUnsavedAttributeValues }: OwnProps) => { +export const RegisterTei = ({ onLink, onSave, onCancel, onGetUnsavedAttributeValues }: OwnProps) => { const dataEntryId = 'relationship'; const itemId = useSelector(({ dataEntries }) => dataEntries[dataEntryId]?.itemId); const error = useSelector(({ newRelationshipRegisterTei }) => (newRelationshipRegisterTei.error)); @@ -30,6 +30,7 @@ export const RegisterTei = ({ onLink, onSave, onGetUnsavedAttributeValues }: Own itemId={itemId} onLink={onLink} onSave={onSave} + onCancel={onCancel} onGetUnsavedAttributeValues={onGetUnsavedAttributeValues} trackedEntityName={trackedEntityName} newRelationshipProgramId={newRelationshipProgramId} diff --git a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/RegisterTei.types.js b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/RegisterTei.types.js index ab47e2ca52..d1dc483194 100644 --- a/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/RegisterTei.types.js +++ b/src/core_modules/capture-core/components/Pages/NewRelationship/RegisterTei/RegisterTei.types.js @@ -9,6 +9,7 @@ type PropsFromRedux = {| export type OwnProps = {| onLink: (teiId: string, values: Object) => void, + onCancel: () => void, onGetUnsavedAttributeValues?: ?Function, onSave: (itemId: string, dataEntryId: string) => void, |}; diff --git a/src/core_modules/capture-core/components/Pages/NewRelationship/TeiRelationship/TeiRelationship.component.js b/src/core_modules/capture-core/components/Pages/NewRelationship/TeiRelationship/TeiRelationship.component.js index 976dcbf749..863327b37f 100644 --- a/src/core_modules/capture-core/components/Pages/NewRelationship/TeiRelationship/TeiRelationship.component.js +++ b/src/core_modules/capture-core/components/Pages/NewRelationship/TeiRelationship/TeiRelationship.component.js @@ -20,6 +20,7 @@ type Props = { onOpenSearch: (trackedEntityTypeId: string, programId: ?string) => void, onSelectFindMode: (findMode: $Values) => void, onAddRelationship: (entity: Object) => void, + onCancel: () => void, selectedRelationshipType: SelectedRelationshipType, classes: { container: string, @@ -143,6 +144,7 @@ class TeiRelationshipPlain extends React.Component { diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/Relationship/ViewEventNewRelationshipWrapper.component.js b/src/core_modules/capture-core/components/Pages/ViewEvent/Relationship/ViewEventNewRelationshipWrapper.component.js index 998b86f7a7..d3cf907c06 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/Relationship/ViewEventNewRelationshipWrapper.component.js +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/Relationship/ViewEventNewRelationshipWrapper.component.js @@ -102,6 +102,7 @@ class ViewEventNewRelationshipWrapperPlain extends React.Component {/* $FlowFixMe[cannot-spread-inexact] automated comment */} @@ -110,7 +111,7 @@ class ViewEventNewRelationshipWrapperPlain extends React.Component text={i18n.t('Leaving this page will discard any selections you made for a new relationship')} destructiveText={i18n.t('Yes, discard changes')} cancelText={i18n.t('No, cancel')} - onDestroy={this.props.onCancel} + onDestroy={onCancel} open={!!this.state.discardDialogOpen} onCancel={this.handleCancelDiscard} /> diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js index 25b215eed7..cea2f79f8f 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/DataEntryEnrollment.component.js @@ -11,6 +11,7 @@ const NewEnrollmentRelationshipPlain = ({ theme, onSave, + onCancel, programId, inheritedAttributes, orgUnitId, @@ -32,6 +33,7 @@ const NewEnrollmentRelationshipPlain = interpolation: { escapeValue: false }, })} onSave={onSave} + onCancel={onCancel} duplicatesReviewPageSize={duplicatesReviewPageSize} renderDuplicatesDialogActions={renderDuplicatesDialogActions} renderDuplicatesCardActions={renderDuplicatesCardActions} diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js index 3b32b17d35..4ab96c8c52 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/Enrollment/dataEntryEnrollment.types.js @@ -15,6 +15,7 @@ export type Props = {| inheritedAttributes: Array, enrollmentMetadata?: Enrollment, onSave: SaveForEnrollmentAndTeiRegistration, + onCancel: () => void, duplicatesReviewPageSize: number, renderDuplicatesCardActions?: RenderCustomCardActions, renderDuplicatesDialogActions?: (onCancel: () => void, onSave: SaveForEnrollmentAndTeiRegistration) => Node, diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js index 20579fc2db..0680da0fa1 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/DataEntryTrackedEntityInstance.js @@ -13,6 +13,7 @@ const RelationshipTrackedEntityInstancePlain = ({ theme, onSave, + onCancel, trackedEntityTypeId, inheritedAttributes, duplicatesReviewPageSize, @@ -38,6 +39,7 @@ const RelationshipTrackedEntityInstancePlain = teiRegistrationMetadata={teiRegistrationMetadata} selectedScopeId={teiRegistrationMetadata.form.id} inheritedAttributes={inheritedAttributes} + onCancel={onCancel} saveButtonText={i18n.t('Save new {{trackedEntityTypeName}} and link', { trackedEntityTypeName: trackedEntityTypeNameLC, interpolation: { escapeValue: false }, })} diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js index 4fcec10567..e473cb96f8 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/DataEntry/TrackedEntityInstance/dataEntryTrackedEntityInstance.types.js @@ -23,6 +23,7 @@ export type Props = {| theme: Theme, trackedEntityTypeId: string, onSave: TeiPayload => void, + onCancel: () => void, teiRegistrationMetadata?: TeiRegistration, inheritedAttributes: Array, duplicatesReviewPageSize: number, diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js index c22abb0c0e..c22f4bc5cf 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/RegisterTei/RegisterTei.component.js @@ -58,6 +58,7 @@ const DialogButtons = ({ onCancel, onSave, trackedEntityName }) => ( const RegisterTeiPlain = ({ dataEntryId, onLink, + onCancel, onSaveWithoutEnrollment, onSaveWithEnrollment, onGetUnsavedAttributeValues, @@ -77,9 +78,9 @@ const RegisterTeiPlain = ({ /> ), [onLink]); - const renderDuplicatesDialogActions = useCallback((onCancel, onSaveArgument) => ( + const renderDuplicatesDialogActions = useCallback((callbackOnCancel, onSaveArgument) => ( @@ -103,6 +104,7 @@ const RegisterTeiPlain = ({ /> void, onGetUnsavedAttributeValues?: ?Function, trackedEntityTypeId: string, + onCancel: () => void, |}; export type ContainerProps = {| diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js index 135dafe53f..b246f5a485 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js @@ -70,6 +70,7 @@ export const TrackedEntityRelationshipsWrapper = ({ suggestedProgramId, onLinkToTrackedEntityFromRegistration, onLinkToTrackedEntityFromSearch, + onCancel, ) => ( console.log('get unsaved')} trackedEntityTypeId={selectedTrackedEntityTypeId} + onCancel={onCancel} /> )} diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/NewTrackedEntityRelationship.component.js b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/NewTrackedEntityRelationship.component.js index 66eae92b47..060eae794c 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/NewTrackedEntityRelationship.component.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/NewTrackedEntityRelationship.component.js @@ -235,6 +235,7 @@ const NewTrackedEntityRelationshipPlain = ({ linkedEntityProgramId, onLinkToTrackedEntityFromRegistration, onLinkToTrackedEntityFromSearch, + onCancel, ); } } @@ -249,6 +250,7 @@ const NewTrackedEntityRelationshipPlain = ({ handleLinkedEntityMetadataSelection, handleNewRetrieverModeSelected, handleSearchRetrieverModeSelected, + onCancel, onLinkToTrackedEntityFromRegistration, onLinkToTrackedEntityFromSearch, programId, diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/NewTrackedEntityRelationship.types.js b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/NewTrackedEntityRelationship.types.js index 95f24c4882..5be15157cf 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/NewTrackedEntityRelationship.types.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/NewTrackedEntityRelationship.types.js @@ -7,16 +7,19 @@ import type { OnSelectFindMode, } from '../WidgetTrackedEntityRelationship.types'; -type RenderTrackedEntitySearch = - (trackedEntityTypeId: string, programId: string, onLinkToTrackedEntity: OnLinkToTrackedEntityFromSearch) => React.Element +type RenderTrackedEntitySearch = ( + trackedEntityTypeId: string, + programId: string, + onLinkToTrackedEntity: OnLinkToTrackedEntityFromSearch, +) => React.Element -type RenderTrackedEntityRegistration = - ( - trackedEntityTypeId: string, - programId: string, - onLinkToTrackedEntityFromRegistration: OnLinkToTrackedEntityFromRegistration, - onLinkToTrackedEntity: OnLinkToTrackedEntityFromSearch, - ) => React.Element +type RenderTrackedEntityRegistration = ( + trackedEntityTypeId: string, + programId: string, + onLinkToTrackedEntityFromRegistration: OnLinkToTrackedEntityFromRegistration, + onLinkToTrackedEntity: OnLinkToTrackedEntityFromSearch, + onCancel: () => void, +) => React.Element export type ContainerProps = $ReadOnly<{| teiId: string, diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/WidgetTrackedEntityRelationship.types.js b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/WidgetTrackedEntityRelationship.types.js index da87a34f42..2d40430a7f 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/WidgetTrackedEntityRelationship.types.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/WidgetTrackedEntityRelationship.types.js @@ -38,6 +38,7 @@ export type WidgetTrackedEntityRelationshipProps = {| programId: string, onLinkToTrackedEntityFromRegistration: OnLinkToTrackedEntityFromRegistration, onLinkToTrackedEntityFromSearch: OnLinkToTrackedEntityFromSearch, + onCancel: () => void, ) => React.Element, renderTrackedEntitySearch?: ( trackedEntityTypeId: string, From 6bc4907c8b75b413a8e044e36cbcd35c3eac2695 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Tue, 5 Dec 2023 12:24:15 +0000 Subject: [PATCH 15/32] chore(release): cut 100.47.1 [skip release] ## [100.47.1](https://github.com/dhis2/capture-app/compare/v100.47.0...v100.47.1) (2023-12-05) ### Bug Fixes * [DHIS2-15694] Cancel button in Relationship ([#3471](https://github.com/dhis2/capture-app/issues/3471)) ([c1dfbdb](https://github.com/dhis2/capture-app/commit/c1dfbdb3352388bba7d51b8bc2b9d033d10967c3)) * [DHIS2-15983] Enrollment date not assigned on form init ([#3475](https://github.com/dhis2/capture-app/issues/3475)) ([a13a766](https://github.com/dhis2/capture-app/commit/a13a766ea463514dfdd090b8d40db6406dac80bb)) --- CHANGELOG.md | 8 ++++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6878dc55d..74d9402de0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## [100.47.1](https://github.com/dhis2/capture-app/compare/v100.47.0...v100.47.1) (2023-12-05) + + +### Bug Fixes + +* [DHIS2-15694] Cancel button in Relationship ([#3471](https://github.com/dhis2/capture-app/issues/3471)) ([c1dfbdb](https://github.com/dhis2/capture-app/commit/c1dfbdb3352388bba7d51b8bc2b9d033d10967c3)) +* [DHIS2-15983] Enrollment date not assigned on form init ([#3475](https://github.com/dhis2/capture-app/issues/3475)) ([a13a766](https://github.com/dhis2/capture-app/commit/a13a766ea463514dfdd090b8d40db6406dac80bb)) + # [100.47.0](https://github.com/dhis2/capture-app/compare/v100.46.1...v100.47.0) (2023-12-03) diff --git a/package.json b/package.json index a510d227de..b980c2de4a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.47.0", + "version": "100.47.1", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.47.0", + "@dhis2/rules-engine-javascript": "100.47.1", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index a894110539..84175439f4 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.47.0", + "version": "100.47.1", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From ba6719a9eefe0a98444f1631f0ac4c1c40d86557 Mon Sep 17 00:00:00 2001 From: eirikhaugstulen Date: Thu, 7 Dec 2023 12:41:43 +0100 Subject: [PATCH 16/32] refactor: [TECH-1541] Replace Material UI Dialog (#3460) --- cypress/e2e/SearchPage/index.js | 1 - .../WidgetsForEventSchedule.feature | 4 +- .../WidgetsForEventSchedule/index.js | 2 +- .../EventWorkingListsUser/index.js | 4 +- .../TeiWorkingListsUser.feature | 22 +++--- .../TeiWorkingListsUser/index.js | 47 +++++++----- .../ExistingTEIContents.component.js | 17 ++--- .../ExistingTEIDialog.component.js | 14 ++-- .../DataEntry/withAskToCreateNew.js | 76 ++++++++++--------- .../ErrorAndWarningDialog.component.js | 22 ++---- .../ErrorDialog.component.js | 24 +++--- .../WarningDialog.component.js | 22 ++---- .../withSaveHandler/withSaveHandler.js | 57 +++++++------- .../Dialogs/DiscardDialog.component.js | 48 +++++++----- .../FeedbackBar/FeedbackBar.component.js | 42 +++++----- .../CoordinateField.component.js | 12 +-- .../PolygonField/PolygonField.component.js | 9 ++- .../ColumnSelectorDialog.component.js | 28 ++++--- .../DialogLoadingMask.component.js | 14 ++-- .../PossibleDuplicatesDialog.component.js | 32 +++----- .../ReviewDialogContents.component.js | 11 ++- .../DataEntry/withDeleteButton.js | 61 ++++++++------- .../DownloadDialog.component.js | 26 ++++--- .../DeleteConfirmationDialog.component.js | 27 +++---- .../ExistingTemplateContents.component.js | 11 ++- .../ExistingTemplateDialog.component.js | 15 ++-- .../NewTemplateContents.component.js | 13 ++-- .../NewTemplateDialog.component.js | 15 ++-- .../SharingDialog.component.js | 3 +- .../TemplateMaintenance.component.js | 1 + .../sharingDialog.types.js | 1 + .../CoordinateField.component.js | 23 ++++-- .../coordinateField.module.css | 8 +- .../PolygonField/PolygonField.component.js | 37 +++++++-- .../PolygonField/polygonField.module.css | 5 +- 35 files changed, 400 insertions(+), 354 deletions(-) diff --git a/cypress/e2e/SearchPage/index.js b/cypress/e2e/SearchPage/index.js index b322ef00bc..644ff73111 100644 --- a/cypress/e2e/SearchPage/index.js +++ b/cypress/e2e/SearchPage/index.js @@ -81,7 +81,6 @@ When('you can close the modal', () => { .contains('Back to search') .click(); cy.get('[data-test="dhis2-uicore-modal"]') - .contains('No results found') .should('not.exist'); }); diff --git a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEventSchedule.feature b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEventSchedule.feature index 277fcb0191..6f021d0886 100644 --- a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEventSchedule.feature +++ b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEventSchedule.feature @@ -1,8 +1,10 @@ Feature: The user interacts with the widgets Schedule tab + # Blocked by DHIS2-16229 + @skip Scenario: User cancel after choose a schedule date in schedule tab Given you land on the enrollment add event page by having typed #/enrollmentEventNew?programId=IpHINAT79UW&orgUnitId=DiszpKrYNg8&teiId=EaOyKGOIGRp&enrollmentId=wBU0RAsYjKE&stageId=A03MvHHogjR&tab=SCHEDULE Then you should see Schedule tab Then you choose a schedule date When you click cancel in Schedule tab - Then you should see confirm dialog \ No newline at end of file + Then you should see confirm dialog diff --git a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEventSchedule/index.js b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEventSchedule/index.js index 1b606aa3c0..3896685c41 100644 --- a/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEventSchedule/index.js +++ b/cypress/e2e/WidgetsForEnrollmentPages/WidgetsForEventSchedule/index.js @@ -18,7 +18,7 @@ When('you click cancel in Schedule tab', () => { }); Then('you should see confirm dialog', () => { - cy.get('[role="dialog"]') + cy.get('aside[role="dialog"]') .find('[data-test="dhis2-uicore-modaltitle"]') .contains('Discard unsaved changes?') .should('exist'); diff --git a/cypress/e2e/WorkingLists/EventWorkingLists/EventWorkingListsUser/index.js b/cypress/e2e/WorkingLists/EventWorkingLists/EventWorkingListsUser/index.js index d16c2a84d7..79dd1acad6 100644 --- a/cypress/e2e/WorkingLists/EventWorkingLists/EventWorkingListsUser/index.js +++ b/cypress/e2e/WorkingLists/EventWorkingLists/EventWorkingListsUser/index.js @@ -148,12 +148,12 @@ When('you open the column selector', () => { }); When('you select Household location and save from the column selector', () => { - cy.get('div[role="dialog"]') + cy.get('aside[role="dialog"]') .contains('Household location') .find('input') .click(); - cy.get('div[role="dialog"]') + cy.get('aside[role="dialog"]') .contains('Save') .click(); }); diff --git a/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser.feature b/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser.feature index b0bdfef1e0..73b30f7668 100644 --- a/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser.feature +++ b/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser.feature @@ -1,5 +1,13 @@ Feature: User interacts with tei working lists + Scenario: The TEI custom working can be shared + Given you open the main page with Ngelehun and Malaria focus investigation context + And you see the custom TEI working lists + And you can load the view with the name Events assigned to me + And you create a copy of the working list + When you change the sharing settings + Then you see the new sharing settings + Scenario: User opens the default working list for a tracker program Given you open the main page with Ngelehun and child programme context Then the default working list should be displayed @@ -81,7 +89,7 @@ When you change rows per page to 10 Then the list should display 10 rows of data And for a tracker program the page navigation should show that you are on the first page -Scenario: Show teis ordered ascendingly by first name +Scenario: Show teis ordered ascendingly by first name Given you open the main page with Ngelehun and child programme context When you click the first name column header Then the sort arrow should indicate ascending order @@ -93,13 +101,7 @@ Given you open the main page with Ngelehun and Malaria focus investigation conte Then you see the custom TEI working lists And you can load the view with the name Events assigned to me -Scenario: The TEI custom working can be shared -Given you open the main page with Ngelehun and Malaria focus investigation context -And you see the custom TEI working lists -And you can load the view with the name Events assigned to me -And you create a copy of the working list -When you change the sharing settings -Then you see the new sharing settings + Scenario: The user creates, updates and deletes a TEI custom working list Given you open the main page with Ngelehun and Malaria case diagnosis context @@ -139,7 +141,7 @@ And you select a data element columns and save from the column selector Then you see data elements specific filters and columns @v>=39 -Scenario: While in a program stage working list, the user can filter by both TEA and data elements +Scenario: While in a program stage working list, the user can filter by both TEA and data elements Given you open the main page with Ngelehun, WHO RMNCH Tracker and First antenatal care visit context When you set the enrollment status filter to active And you apply the current filter @@ -152,7 +154,7 @@ And you apply the current filter Then the list should display 1 row of data @v>=39 -Scenario: While in a program stage working list, the user can sort by both TEA and data elements +Scenario: While in a program stage working list, the user can sort by both TEA and data elements Given you open the main page with Ngelehun, WHO RMNCH Tracker and First antenatal care visit context And you set the first name filter to u And you apply the current filter diff --git a/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser/index.js b/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser/index.js index 1c1574e25d..c6adb4c683 100644 --- a/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser/index.js +++ b/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser/index.js @@ -246,12 +246,12 @@ When('you open the column selector', () => { }); When('you select the registering unit and save from the column selector', () => { - cy.get('div[role="dialog"]') + cy.get('aside[role="dialog"]') .contains('Registering unit') .find('input') .click(); - cy.get('div[role="dialog"]') + cy.get('aside[role="dialog"]') .contains('Save') .click(); }); @@ -544,27 +544,32 @@ Then('you see the new sharing settings', () => { .click(); }); -When('you create a copy of the working list', () => { - cy.get('[data-test="list-view-menu-button"]') - .click(); +When('you create a copy of the working list', + () => { + cy.get('[data-test="list-view-menu-button"]') + .click(); - cy.contains('Save current view as') - .click(); + cy.contains('Save current view as') + .click(); - const id = uuid(); - cy.get('[data-test="view-name-content"]') - .type(id); + const id = uuid(); + cy.get('[data-test="view-name-content"]') + .type(id); - cy.intercept('POST', '**/trackedEntityInstanceFilters**').as('newTrackerFilter'); + cy.intercept('POST', '**/trackedEntityInstanceFilters**') + .as('newTrackerFilter'); - cy.get('button') - .contains('Save') - .click(); + cy.get('[data-test="new-template-dialog"]') + .within(() => { + cy.get('[data-test="dhis2-uicore-button"]') + .contains('Save') + .click(); + }); - cy.wait('@newTrackerFilter', { timeout: 30000 }); + cy.wait('@newTrackerFilter', { timeout: 30000 }); - cy.reload(); -}); + cy.reload(); + }); When('you open the program stage filters from the more filters dropdown menu', () => { cy.get('[data-test="tei-working-lists"]') @@ -602,12 +607,12 @@ When('you select the Foci response program stage', () => { }); When('you select a data element columns and save from the column selector', () => { - cy.get('div[role="dialog"]') + cy.get('aside[role="dialog"]') .contains('People included') .find('input') .click(); - cy.get('div[role="dialog"]') + cy.get('aside[role="dialog"]') .contains('Save') .click(); }); @@ -663,12 +668,12 @@ Then('you see scheduledAt filter', () => { }); When('you select a scheduledAt column and save from the column selector', () => { - cy.get('div[role="dialog"]') + cy.get('aside[role="dialog"]') .contains('Appointment date') .find('input') .click(); - cy.get('div[role="dialog"]') + cy.get('aside[role="dialog"]') .contains('Save') .click(); }); diff --git a/src/core_modules/capture-core/components/DataEntries/withErrorMessagePostProcessor/UniqueTEADuplicate/ExistingTEIContents.component.js b/src/core_modules/capture-core/components/DataEntries/withErrorMessagePostProcessor/UniqueTEADuplicate/ExistingTEIContents.component.js index 8d919e73e2..7bfed86fa6 100644 --- a/src/core_modules/capture-core/components/DataEntries/withErrorMessagePostProcessor/UniqueTEADuplicate/ExistingTEIContents.component.js +++ b/src/core_modules/capture-core/components/DataEntries/withErrorMessagePostProcessor/UniqueTEADuplicate/ExistingTEIContents.component.js @@ -2,10 +2,7 @@ import React, { type ComponentType } from 'react'; import { withStyles } from '@material-ui/core/styles'; import i18n from '@dhis2/d2-i18n'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import DialogActions from '@material-ui/core/DialogActions'; -import { Button } from '@dhis2/ui'; +import { Button, ModalContent, ModalTitle, ModalActions } from '@dhis2/ui'; import { CardList } from '../../../CardList'; import type { Props } from './existingTeiContents.types'; @@ -35,18 +32,18 @@ const ExistingTEIContentsComponentPlain = ({ return ( - - + + {i18n.t('Registered person')} - + - - + + - - - - - ) + renderAskToCreateNewModal = () => { + if (!this.state.isOpen) { + return null; + } + + return ( + + + {i18n.t('Generate new event')} + + + {i18n.t('Do you want to create another event?')} + + + + + + + + + ); + } render() { const { onSave, ...passOnProps } = this.props; diff --git a/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/ErrorAndWarningDialog.component.js b/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/ErrorAndWarningDialog.component.js index 203faee0b5..0b92900d0b 100644 --- a/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/ErrorAndWarningDialog.component.js +++ b/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/ErrorAndWarningDialog.component.js @@ -1,12 +1,8 @@ // @flow import * as React from 'react'; import { withStyles } from '@material-ui/core'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; import i18n from '@dhis2/d2-i18n'; -import { Button } from '@dhis2/ui'; +import { Button, ModalTitle, ModalContent, ModalActions } from '@dhis2/ui'; const getStyles = (theme: Theme) => ({ errors: { @@ -134,17 +130,15 @@ class ErrorAndWarningDialogPlain extends React.Component { render() { return ( - + {i18n.t('Validation errors and warnings')} - - - - {this.getContents()} - - - + + + {this.getContents()} + + {this.getButtons()} - + ); } diff --git a/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/ErrorDialog.component.js b/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/ErrorDialog.component.js index 8d17307161..25d60ad5f2 100644 --- a/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/ErrorDialog.component.js +++ b/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/ErrorDialog.component.js @@ -1,11 +1,7 @@ // @flow import * as React from 'react'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; import i18n from '@dhis2/d2-i18n'; -import { Button } from '@dhis2/ui'; +import { Button, ModalTitle, ModalContent, ModalActions } from '@dhis2/ui'; import { withStyles } from '@material-ui/core'; type Props = { @@ -52,7 +48,7 @@ class ErrorDialogPlain extends React.Component { const { onAbort, onSave, saveEnabled, classes } = this.props; return ( -
+
@@ -73,17 +69,15 @@ class ErrorDialogPlain extends React.Component { render() { return ( - + {i18n.t('Validation errors')} - - - - {this.getContents()} - - - + + + {this.getContents()} + + {this.getButtons()} - + ); } diff --git a/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/WarningDialog.component.js b/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/WarningDialog.component.js index 4510553cca..ff95f00ee1 100644 --- a/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/WarningDialog.component.js +++ b/src/core_modules/capture-core/components/DataEntry/withSaveHandler/MessagesDialogContents/WarningDialog.component.js @@ -1,11 +1,7 @@ // @flow import * as React from 'react'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; import i18n from '@dhis2/d2-i18n'; -import { Button } from '@dhis2/ui'; +import { Button, ModalTitle, ModalContent, ModalActions } from '@dhis2/ui'; import { withStyles } from '@material-ui/core'; type Props = { @@ -51,15 +47,13 @@ class WarningDialogPlain extends React.Component { const { onAbort, onSave, classes } = this.props; return ( - + {i18n.t('Validation warnings')} - - - - {this.getContents()} - - - + + + {this.getContents()} + +
-
+
); } diff --git a/src/core_modules/capture-core/components/DataEntry/withSaveHandler/withSaveHandler.js b/src/core_modules/capture-core/components/DataEntry/withSaveHandler/withSaveHandler.js index d8e90bfc3c..a58549fd2b 100644 --- a/src/core_modules/capture-core/components/DataEntry/withSaveHandler/withSaveHandler.js +++ b/src/core_modules/capture-core/components/DataEntry/withSaveHandler/withSaveHandler.js @@ -1,10 +1,7 @@ // @flow import * as React from 'react'; import log from 'loglevel'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; +import { Modal, ModalContent, ModalTitle } from '@dhis2/ui'; import { connect } from 'react-redux'; import i18n from '@dhis2/d2-i18n'; import { errorCreator } from 'capture-core-utils'; @@ -248,32 +245,34 @@ const getSaveHandler = ( onSave={this.handleSaveAttempt} {...filteredProps} /> - - - - - - {i18n.t('Operations running')} - - - + {this.state.messagesDialogOpen && ( + + + + )} + {this.state.waitForPromisesDialogOpen && ( + + + {i18n.t('Operations running')} + + {this.getDialogWaitForUploadContents()} - - - + + + )}
); } diff --git a/src/core_modules/capture-core/components/Dialogs/DiscardDialog.component.js b/src/core_modules/capture-core/components/Dialogs/DiscardDialog.component.js index 257852c7d8..926637ec0a 100644 --- a/src/core_modules/capture-core/components/Dialogs/DiscardDialog.component.js +++ b/src/core_modules/capture-core/components/Dialogs/DiscardDialog.component.js @@ -5,24 +5,32 @@ import type { Props } from './discardDialog.types'; export const DiscardDialog = ({ open, header, text, cancelText, onCancel, destructiveText, onDestroy, -}: Props) => ( - - - {header} - - - {text} - - - - - - - - -); +}: Props) => { + if (!open) { + return null; + } + + return ( + + + {header} + + +
+ {text} +
+
+ + + + + + +
+ ); +}; diff --git a/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.js b/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.js index c6b1fe0a49..f4406742cc 100644 --- a/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.js +++ b/src/core_modules/capture-core/components/FeedbackBar/FeedbackBar.component.js @@ -1,13 +1,9 @@ // @flow import * as React from 'react'; import SnackBar from '@material-ui/core/Snackbar'; -import Dialog from '@material-ui/core/Dialog'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogTitle from '@material-ui/core/DialogTitle'; import { withStyles } from '@material-ui/core/styles'; import { IconButton } from 'capture-ui'; -import { IconCross24, Button } from '@dhis2/ui'; +import { IconCross24, Button, Modal, ModalTitle, ModalContent, ModalActions } from '@dhis2/ui'; import i18n from '@dhis2/d2-i18n'; import isDefined from 'd2-utilizr/lib/isDefined'; @@ -100,25 +96,27 @@ class Index extends React.Component { message={{message}} action={this.getAction()} /> - - - { + {isDialogOpen && ( + + + { // $FlowFixMe[prop-missing] automated comment - isDialogOpen ? message && message.title : ''} - - - { + isDialogOpen ? message && message.title : ''} + + + { // $FlowFixMe[prop-missing] automated comment - isDialogOpen ? message && message.content : ''} - - - - - + isDialogOpen ? message && message.content : ''} + + + + + + )} ); } diff --git a/src/core_modules/capture-core/components/FormFields/New/Fields/CoordinateField/CoordinateField.component.js b/src/core_modules/capture-core/components/FormFields/New/Fields/CoordinateField/CoordinateField.component.js index 9ac8d6931c..992b6b069d 100644 --- a/src/core_modules/capture-core/components/FormFields/New/Fields/CoordinateField/CoordinateField.component.js +++ b/src/core_modules/capture-core/components/FormFields/New/Fields/CoordinateField/CoordinateField.component.js @@ -2,8 +2,7 @@ import * as React from 'react'; import withStyles from '@material-ui/core/styles/withStyles'; import { CoordinateField as UICoordinateField } from 'capture-ui'; -import Dialog from '@material-ui/core/Dialog'; -import DialogTitle from '@material-ui/core/DialogTitle'; +import { Modal, ModalTitle } from '@dhis2/ui'; import { typeof orientations } from '../../../New'; const getStyles = (theme: Theme) => ({ @@ -80,11 +79,12 @@ class CoordinateFieldPlain extends React.Component { // $FlowFixMe[cannot-spread-inexact] automated comment - {dialogLabel} - + {dialogLabel} + } {...passOnProps} classes={this.passOnClasses} diff --git a/src/core_modules/capture-core/components/FormFields/New/Fields/PolygonField/PolygonField.component.js b/src/core_modules/capture-core/components/FormFields/New/Fields/PolygonField/PolygonField.component.js index 058d82c9c9..47831a9a47 100644 --- a/src/core_modules/capture-core/components/FormFields/New/Fields/PolygonField/PolygonField.component.js +++ b/src/core_modules/capture-core/components/FormFields/New/Fields/PolygonField/PolygonField.component.js @@ -2,7 +2,7 @@ import * as React from 'react'; import withStyles from '@material-ui/core/styles/withStyles'; import { PolygonField as UIPolygonField } from 'capture-ui'; -import { Dialog, DialogTitle } from '@material-ui/core'; +import { Modal, ModalTitle } from '@dhis2/ui'; import { typeof orientations } from '../../../New'; const getStyles = () => ({ @@ -44,11 +44,12 @@ class PolygonFieldPlain extends React.Component { // $FlowFixMe[cannot-spread-inexact] automated comment - {dialogLabel} - + {dialogLabel} + } {...passOnProps} /> diff --git a/src/core_modules/capture-core/components/ListView/ColumnSelector/ColumnSelectorDialog.component.js b/src/core_modules/capture-core/components/ListView/ColumnSelector/ColumnSelectorDialog.component.js index 6cbe5aa034..ff0bad9c19 100644 --- a/src/core_modules/capture-core/components/ListView/ColumnSelector/ColumnSelectorDialog.component.js +++ b/src/core_modules/capture-core/components/ListView/ColumnSelector/ColumnSelectorDialog.component.js @@ -1,11 +1,7 @@ // @flow import React, { useState, useEffect } from 'react'; import { isEqual } from 'lodash'; -import { Button } from '@dhis2/ui'; -import Dialog from '@material-ui/core/Dialog'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogTitle from '@material-ui/core/DialogTitle'; +import { Modal, ModalTitle, ModalContent, ModalActions, Button } from '@dhis2/ui'; import i18n from '@dhis2/d2-i18n'; import { DragDropList } from './DragDropList'; @@ -40,23 +36,31 @@ export const ColumnSelectorDialog = ({ columns, open, onClose, onSave }: Props) setColumnList(sortedList); }; + if (!open) { + return null; + } + return ( - - {i18n.t('Columns to show in table')} - + + {i18n.t('Columns to show in table')} + - - + + - - + + ); }; diff --git a/src/core_modules/capture-core/components/LoadingMasks/DialogLoadingMask.component.js b/src/core_modules/capture-core/components/LoadingMasks/DialogLoadingMask.component.js index 0366b2b095..1acc9e6a1c 100644 --- a/src/core_modules/capture-core/components/LoadingMasks/DialogLoadingMask.component.js +++ b/src/core_modules/capture-core/components/LoadingMasks/DialogLoadingMask.component.js @@ -1,8 +1,6 @@ // @flow import React, { Component } from 'react'; -import { CircularLoader } from '@dhis2/ui'; -import Dialog from '@material-ui/core/Dialog'; -import DialogContent from '@material-ui/core/DialogContent'; +import { CircularLoader, Modal, ModalContent } from '@dhis2/ui'; type Props = { }; @@ -10,13 +8,13 @@ type Props = { export class DialogLoadingMask extends Component { render() { return ( - - + - - + + ); } } diff --git a/src/core_modules/capture-core/components/PossibleDuplicatesDialog/PossibleDuplicatesDialog.component.js b/src/core_modules/capture-core/components/PossibleDuplicatesDialog/PossibleDuplicatesDialog.component.js index 5a35b3ff34..85a1fccc19 100644 --- a/src/core_modules/capture-core/components/PossibleDuplicatesDialog/PossibleDuplicatesDialog.component.js +++ b/src/core_modules/capture-core/components/PossibleDuplicatesDialog/PossibleDuplicatesDialog.component.js @@ -1,8 +1,6 @@ // @flow import * as React from 'react'; -import { withStyles } from '@material-ui/core'; -import Dialog from '@material-ui/core/Dialog'; -import DialogActions from '@material-ui/core/DialogActions'; +import { Modal, ModalActions } from '@dhis2/ui'; import { ReviewDialogContents } from './ReviewDialogContents/ReviewDialogContents.container'; import type { RenderCustomCardActions } from '../CardList/CardList.types'; @@ -15,37 +13,29 @@ type Props = {| selectedScopeId: string |}; -const StyledDialogActions = withStyles({ - root: { margin: 24 }, -})(DialogActions); - class ReviewDialogClass extends React.Component { - static paperProps = { - style: { - maxHeight: 'calc(100% - 100px)', - }, - }; - render() { const { open, onCancel, extraActions, selectedScopeId, dataEntryId, renderCardActions } = this.props; + if (!open) { + return null; + } + return ( - - + {extraActions} - - + + ); } } diff --git a/src/core_modules/capture-core/components/PossibleDuplicatesDialog/ReviewDialogContents/ReviewDialogContents.component.js b/src/core_modules/capture-core/components/PossibleDuplicatesDialog/ReviewDialogContents/ReviewDialogContents.component.js index 99c01c200c..d5146481cb 100644 --- a/src/core_modules/capture-core/components/PossibleDuplicatesDialog/ReviewDialogContents/ReviewDialogContents.component.js +++ b/src/core_modules/capture-core/components/PossibleDuplicatesDialog/ReviewDialogContents/ReviewDialogContents.component.js @@ -1,8 +1,7 @@ // @flow import React, { type ComponentType, useContext } from 'react'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogTitle from '@material-ui/core/DialogTitle'; import { withStyles } from '@material-ui/core/styles'; +import { ModalTitle, ModalContent } from '@dhis2/ui'; import i18n from '@dhis2/d2-i18n'; import { CardList } from '../../CardList'; import { ReviewDialogContentsPager } from './ReviewDialogContentsPager.container'; @@ -30,10 +29,10 @@ const ReviewDialogContentsPlain = ({ const { resultsPageSize } = useContext(ResultsPageSizeContext); return ( - - + + {i18n.t('Possible duplicates found')} - + - + ); }; diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/withDeleteButton.js b/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/withDeleteButton.js index 14efa04273..1c55b9ed1b 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/withDeleteButton.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/withDeleteButton.js @@ -39,33 +39,40 @@ const getDeleteButton = (InnerComponent: React.ComponentType) => {i18n.t('Delete')} - - - {i18n.t('Delete event')} - - - {i18n.t('Deleting an event is permanent and cannot be undone.' + ' ' + - 'Are you sure you want to delete this event? ')} - - - - - - - - + {this.state.isOpen && ( + + + {i18n.t('Delete event')} + + + {i18n.t('Deleting an event is permanent and cannot be undone.' + ' ' + + 'Are you sure you want to delete this event? ')} + + + + + + + + + )}
) : null ) diff --git a/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/ViewMenuSetup/DownloadDialog/DownloadDialog.component.js b/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/ViewMenuSetup/DownloadDialog/DownloadDialog.component.js index fc79445ce2..0ed117534b 100644 --- a/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/ViewMenuSetup/DownloadDialog/DownloadDialog.component.js +++ b/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/ViewMenuSetup/DownloadDialog/DownloadDialog.component.js @@ -3,8 +3,7 @@ import React, { PureComponent, type ComponentType } from 'react'; import i18n from '@dhis2/d2-i18n'; import { withStyles } from '@material-ui/core/styles'; -import { Dialog, DialogTitle, DialogContent, DialogActions } from '@material-ui/core'; -import { Button } from '@dhis2/ui'; +import { Button, Modal, ModalTitle, ModalContent, ModalActions } from '@dhis2/ui'; import type { Props } from './downloadDialog.types'; const getStyles = () => ({ @@ -80,23 +79,28 @@ class DownloadDialogPlain extends PureComponent { } render() { const { open, onClose } = this.props; + + if (!open) { + return null; + } + return ( - - {i18n.t('Download with current filters')} - + {i18n.t('Download with current filters')} + {this.renderButtons()} - - + + - - + + ); } diff --git a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/DeleteConfirmationDialog.component.js b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/DeleteConfirmationDialog.component.js index 137dab9b63..635bac6d3e 100644 --- a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/DeleteConfirmationDialog.component.js +++ b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/DeleteConfirmationDialog.component.js @@ -2,8 +2,7 @@ import * as React from 'react'; import { withStyles } from '@material-ui/core/styles'; import i18n from '@dhis2/d2-i18n'; -import { Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } from '@material-ui/core'; -import { Button } from '@dhis2/ui'; +import { Button, Modal, ModalTitle, ModalContent, ModalActions } from '@dhis2/ui'; const getStyles = () => ({ buttonContainer: { @@ -29,18 +28,20 @@ const DeleteConfirmationDialogPlain = (props: Props) => { classes, } = props; + if (!open) { + return null; + } + return ( - - {i18n.t('Delete view')} - - - {i18n.t('Do you really want to delete the \'{{templateName}}\' view?', { templateName })} - - - {i18n.t('Delete view')} + + {i18n.t('Do you really want to delete the \'{{templateName}}\' view?', { templateName })} + + - - + + ); }; diff --git a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/ExistingTemplateContents.component.js b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/ExistingTemplateContents.component.js index 28b526c2cb..0efef529f0 100644 --- a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/ExistingTemplateContents.component.js +++ b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/ExistingTemplateContents.component.js @@ -2,8 +2,7 @@ import * as React from 'react'; import { withStyles } from '@material-ui/core/styles'; import i18n from '@dhis2/d2-i18n'; -import { DialogTitle, DialogContent, DialogActions } from '@material-ui/core'; -import { Button } from '@dhis2/ui'; +import { Button, ModalTitle, ModalContent, ModalActions } from '@dhis2/ui'; const getStyles = () => ({ buttonContainer: { @@ -22,9 +21,9 @@ const ExistingTemplateContentsPlain = (props: Props) => { const { onSaveTemplate, onClose, classes } = props; return ( - {i18n.t('Save')} - - {i18n.t('Save')} + + - + ); }; diff --git a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/ExistingTemplateDialog.component.js b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/ExistingTemplateDialog.component.js index e8e1af626e..da394131b6 100644 --- a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/ExistingTemplateDialog.component.js +++ b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/ExistingTemplateDialog.component.js @@ -1,6 +1,6 @@ // @flow import * as React from 'react'; -import { Dialog } from '@material-ui/core'; +import { Modal } from '@dhis2/ui'; import { ExistingTemplateContents } from './ExistingTemplateContents.component'; type Props = { @@ -16,16 +16,21 @@ export const ExistingTemplateDialog = (props: Props) => { onSaveTemplate, } = props; + if (!open) { + return null; + } + return ( - - + ); }; diff --git a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/NewTemplateContents.component.js b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/NewTemplateContents.component.js index 460069e359..c064f74893 100644 --- a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/NewTemplateContents.component.js +++ b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/NewTemplateContents.component.js @@ -1,9 +1,8 @@ // @flow import * as React from 'react'; -import { colors, Button } from '@dhis2/ui'; +import { colors, Button, ModalTitle, ModalContent, ModalActions } from '@dhis2/ui'; import { withStyles } from '@material-ui/core/styles'; import i18n from '@dhis2/d2-i18n'; -import { DialogTitle, DialogContent, DialogActions } from '@material-ui/core'; import { NewTemplateTextField } from './NewTemplateTextField.component'; const getStyles = (theme: Theme) => ({ @@ -46,8 +45,8 @@ const NewTemplateContentsPlain = (props: Props) => { return ( - {i18n.t('Save As view')} - + {i18n.t('Save As view')} + { > {error} - - + - + ); }; diff --git a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/NewTemplateDialog.component.js b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/NewTemplateDialog.component.js index d10a394168..60859c6f5a 100644 --- a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/NewTemplateDialog.component.js +++ b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/NewTemplateDialog.component.js @@ -1,6 +1,6 @@ // @flow import * as React from 'react'; -import { Dialog } from '@material-ui/core'; +import { Modal } from '@dhis2/ui'; import { NewTemplateContents } from './NewTemplateContents.component'; type Props = { @@ -16,16 +16,21 @@ export const NewTemplateDialog = (props: Props) => { onSaveTemplate, } = props; + if (!open) { + return null; + } + return ( - - + ); }; diff --git a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/SharingDialog.component.js b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/SharingDialog.component.js index 173f3ebfd2..9434601bea 100644 --- a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/SharingDialog.component.js +++ b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/SharingDialog.component.js @@ -12,7 +12,7 @@ const styles = { }, }; -const SharingDialogPlain = ({ onClose, open, templateId, classes, templateSharingType }: Props) => { +const SharingDialogPlain = ({ onClose, open, templateId, classes, templateSharingType, dataTest }: Props) => { const { refetch } = useDataQuery( useMemo( () => ({ @@ -61,6 +61,7 @@ const SharingDialogPlain = ({ onClose, open, templateId, classes, templateSharin id={templateId} onClose={handleClose} className={classes.dialog} + dataTest={dataTest} /> : null ); }; diff --git a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/TemplateMaintenance.component.js b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/TemplateMaintenance.component.js index 6167966094..714ff7177a 100644 --- a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/TemplateMaintenance.component.js +++ b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/TemplateMaintenance.component.js @@ -65,6 +65,7 @@ const TemplateMaintenancePlain = (props: Props, ref) => { templateId={currentTemplate.id} onClose={handleSetSharingSettings} templateSharingType={templateSharingType} + dataTest={'sharing-dialog'} /> ); diff --git a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/sharingDialog.types.js b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/sharingDialog.types.js index d2abcf26b2..9eed85d346 100644 --- a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/sharingDialog.types.js +++ b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateMaintenance/sharingDialog.types.js @@ -6,5 +6,6 @@ export type Props = {| open: boolean, templateId: string, templateSharingType: string, + dataTest: string, ...CssClasses, |}; diff --git a/src/core_modules/capture-ui/CoordinateField/CoordinateField.component.js b/src/core_modules/capture-ui/CoordinateField/CoordinateField.component.js index 48eecdaca7..568cb0cedc 100644 --- a/src/core_modules/capture-ui/CoordinateField/CoordinateField.component.js +++ b/src/core_modules/capture-ui/CoordinateField/CoordinateField.component.js @@ -4,7 +4,7 @@ import classNames from 'classnames'; import i18n from '@dhis2/d2-i18n'; import { Map, TileLayer, Marker, withLeaflet } from 'react-leaflet'; import { ReactLeafletSearch } from 'react-leaflet-search-unpolyfilled'; -import { IconCross24, Button } from '@dhis2/ui'; +import { IconCross24, Button, ModalActions, ModalContent } from '@dhis2/ui'; import { IconButton } from 'capture-ui'; import { AddLocationIcon } from '../Icons'; import { CoordinateInput } from '../internal/CoordinateInput/CoordinateInput.component'; @@ -56,6 +56,13 @@ export class CoordinateField extends React.Component { }; } + componentDidUpdate() { + // Invalidate map size to fix rendering bug + if (this.mapInstance && this.state.showMap) { + this.mapInstance.leafletElement.invalidateSize(); + } + } + toSixDecimal = (value: string) => (parseFloat(value) ? parseFloat(value).toFixed(6) : null) handleBlur = (key: string, value: any) => { @@ -139,13 +146,15 @@ export class CoordinateField extends React.Component { const clonedDialog = React.cloneElement( this.props.mapDialog, - { open: this.state.showMap, onClose: this.closeMap }, + { hide: !this.state.showMap, onClose: this.closeMap }, [...React.Children.toArray(this.props.mapDialog.props.children), ( -
- {this.renderMap()} + <> + + {this.renderMap()} + {this.renderDialogActions()} -
+ )], ); return clonedDialog; @@ -185,7 +194,7 @@ export class CoordinateField extends React.Component { } renderDialogActions = () => ( -
+
{/* $FlowFixMe[prop-missing] automated comment */}
-
+ ); renderLatitude = () => { diff --git a/src/core_modules/capture-ui/CoordinateField/coordinateField.module.css b/src/core_modules/capture-ui/CoordinateField/coordinateField.module.css index d73c64bcf2..9f5709617c 100644 --- a/src/core_modules/capture-ui/CoordinateField/coordinateField.module.css +++ b/src/core_modules/capture-ui/CoordinateField/coordinateField.module.css @@ -3,7 +3,7 @@ display: flex; flex-direction: column; } - + .coordinateFieldsHorizontal { position: relative; display: flex; @@ -64,6 +64,8 @@ .mapContainer { flex-grow: 1; position: relative; + height: 100%; + width: 100%; } .leafletContainer { @@ -73,13 +75,11 @@ } .dialogContent { - flex-grow: 1; display: flex; + height: 600px; flex-direction: column; - padding: 0px 24px 24px 24px; } .buttonsContainerVertical { display: flex; } - \ No newline at end of file diff --git a/src/core_modules/capture-ui/PolygonField/PolygonField.component.js b/src/core_modules/capture-ui/PolygonField/PolygonField.component.js index fd2bfe043a..7ef585a16c 100644 --- a/src/core_modules/capture-ui/PolygonField/PolygonField.component.js +++ b/src/core_modules/capture-ui/PolygonField/PolygonField.component.js @@ -1,7 +1,7 @@ // @flow import * as React from 'react'; import i18n from '@dhis2/d2-i18n'; -import { IconCheckmark16, IconLocation16, colors, Button } from '@dhis2/ui'; +import { IconCheckmark16, IconLocation16, colors, Button, ModalContent, ModalActions } from '@dhis2/ui'; import L from 'leaflet'; import { Map, TileLayer, FeatureGroup, withLeaflet } from 'react-leaflet'; import { ReactLeafletSearch } from 'react-leaflet-search-unpolyfilled'; @@ -62,6 +62,8 @@ function coordsToFeatureCollection(coordinates): ?FeatureCollection { } export class PolygonField extends React.Component { + mapInstance: ?any; + static defaultProps = { mapCenter: [51.505, -0.09], } @@ -75,6 +77,13 @@ export class PolygonField extends React.Component { }; } + componentDidUpdate() { + // Invalidate map size to fix rendering bug + if (this.mapInstance && this.state.showMap) { + this.mapInstance.leafletElement.invalidateSize(); + } + } + onFeatureGroupReady = (reactFGref: any, featureCollection: ?FeatureCollection) => { if (featureCollection) { const leafletGeoJSON = new L.GeoJSON(featureCollection); @@ -134,19 +143,25 @@ export class PolygonField extends React.Component { this.closeMap(); } + setMapInstance = (mapInstance: any) => { + this.mapInstance = mapInstance; + } + renderMapDialog = () => { const clonedDialog = React.cloneElement( // $FlowFixMe[incompatible-type] automated comment this.props.mapDialog, - { open: this.state.showMap, onClose: this.closeMap }, + { hide: !this.state.showMap, onClose: this.closeMap }, // $FlowFixMe[incompatible-use] automated comment [...React.Children.toArray(this.props.mapDialog.props.children), ( -
- {this.renderMap()} + <> + + {this.renderMap()} + {this.renderDialogActions()} -
+ )], ); return clonedDialog; @@ -159,7 +174,13 @@ export class PolygonField extends React.Component { const center = this.getCenter(featureCollection); return (
- + { this.setMapInstance(mapInstance); }} + > { } renderDialogActions = () => ( -
+
{/* $FlowFixMe[prop-missing] automated comment */}
-
+ ); render() { diff --git a/src/core_modules/capture-ui/PolygonField/polygonField.module.css b/src/core_modules/capture-ui/PolygonField/polygonField.module.css index 3aa0c0454f..f4fa6c640e 100644 --- a/src/core_modules/capture-ui/PolygonField/polygonField.module.css +++ b/src/core_modules/capture-ui/PolygonField/polygonField.module.css @@ -21,6 +21,8 @@ .mapContainer { flex-grow: 1; position: relative; + width: 100%; + height: 100%; } .map { @@ -30,9 +32,8 @@ } .dialogContent { - flex-grow: 1; display: flex; flex-direction: column; - padding: 0px 24px 24px 24px; + height: 600px; } From 1a4e7482467656e19ce58f34862a306e6ae008cc Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Sun, 10 Dec 2023 02:38:19 +0100 Subject: [PATCH 17/32] fix(translations): sync translations from transifex (master) Automatically merged. --- i18n/zh.po | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/i18n/zh.po b/i18n/zh.po index 5723afede3..16ff6d9de3 100644 --- a/i18n/zh.po +++ b/i18n/zh.po @@ -1,16 +1,16 @@ # # Translators: # Philip Larsen Donnelly, 2022 -# easylin , 2023 # 晓东 林 <13981924470@126.com>, 2023 # Viktor Varland , 2023 +# easylin , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Viktor Varland , 2023\n" +"Last-Translator: easylin , 2023\n" "Language-Team: Chinese (https://app.transifex.com/hisp-uio/teams/100509/zh/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -1159,7 +1159,7 @@ msgid "Edit" msgstr "编辑" msgid "Set coordinates" -msgstr "" +msgstr "设置坐标" msgid "Coordinates" msgstr "坐标" @@ -1168,10 +1168,10 @@ msgid "Delete polygon" msgstr "删除多边形" msgid "Close without saving" -msgstr "" +msgstr "关闭而不保存" msgid "Finish drawing before saving" -msgstr "" +msgstr "保存前完成绘制" msgid "Set area" msgstr "设置区域" @@ -1201,10 +1201,10 @@ msgid "Cancelled" msgstr "已取消" msgid "Add coordinates" -msgstr "" +msgstr "添加坐标" msgid "Add area" -msgstr "" +msgstr "添加区域" msgid "Comments about this enrollment" msgstr "关于本次报名的评论" From a934291b18248d250739d8c732343bfe1a005c8c Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Sun, 10 Dec 2023 01:46:35 +0000 Subject: [PATCH 18/32] chore(release): cut 100.47.2 [skip release] ## [100.47.2](https://github.com/dhis2/capture-app/compare/v100.47.1...v100.47.2) (2023-12-10) ### Bug Fixes * **translations:** sync translations from transifex (master) ([1a4e748](https://github.com/dhis2/capture-app/commit/1a4e7482467656e19ce58f34862a306e6ae008cc)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74d9402de0..7d367c7378 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [100.47.2](https://github.com/dhis2/capture-app/compare/v100.47.1...v100.47.2) (2023-12-10) + + +### Bug Fixes + +* **translations:** sync translations from transifex (master) ([1a4e748](https://github.com/dhis2/capture-app/commit/1a4e7482467656e19ce58f34862a306e6ae008cc)) + ## [100.47.1](https://github.com/dhis2/capture-app/compare/v100.47.0...v100.47.1) (2023-12-05) diff --git a/package.json b/package.json index b980c2de4a..2a9f6bfdf8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.47.1", + "version": "100.47.2", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.47.1", + "@dhis2/rules-engine-javascript": "100.47.2", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index 84175439f4..ae68b52d3a 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.47.1", + "version": "100.47.2", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From 3579fc05d02f6210f381f93414d07b60a0cfea53 Mon Sep 17 00:00:00 2001 From: eirikhaugstulen Date: Thu, 14 Dec 2023 15:07:58 +0100 Subject: [PATCH 19/32] fix: [DHIS2-16084] Filter unidirectional relationship types (#3477) --- ...kedEntityRelationshipsWrapper.component.js | 2 +- ...dgetTrackedEntityRelationship.component.js | 48 +++++++++++-------- .../RelationshipsWidget.component.js | 7 +-- .../relationshipsWidget.types.js | 4 +- .../useGroupedLinkedEntities.js | 27 ++++++----- .../useRelationships/useRelationships.js | 39 +++++++++++++-- 6 files changed, 86 insertions(+), 41 deletions(-) diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js index b246f5a485..7be6a4a07b 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js @@ -47,7 +47,7 @@ export const TrackedEntityRelationshipsWrapper = ({ ); } - if (!relationshipTypes || !addRelationshipRenderElement) { + if (!relationshipTypes?.length || !addRelationshipRenderElement) { return null; } diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/WidgetTrackedEntityRelationship.component.js b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/WidgetTrackedEntityRelationship.component.js index 6037269107..8af24e2195 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/WidgetTrackedEntityRelationship.component.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/WidgetTrackedEntityRelationship.component.js @@ -6,6 +6,7 @@ import { RelationshipsWidget } from '../common/RelationshipsWidget'; import { RelationshipSearchEntities, useRelationships } from '../common/useRelationships'; import { NewTrackedEntityRelationship } from './NewTrackedEntityRelationship'; import { useTrackedEntityTypeName } from './hooks/useTrackedEntityTypeName'; +import { useRelationshipTypes } from '../common/RelationshipsWidget/useRelationshipTypes'; export const WidgetTrackedEntityRelationship = ({ relationshipTypes: cachedRelationshipTypes, @@ -21,8 +22,17 @@ export const WidgetTrackedEntityRelationship = ({ renderTrackedEntitySearch, renderTrackedEntityRegistration, }: WidgetTrackedEntityRelationshipProps) => { - const { data: relationships, isError, isLoading: isLoadingRelationships } = useRelationships(teiId, RelationshipSearchEntities.TRACKED_ENTITY); + const { data: relationshipTypes } = useRelationshipTypes(cachedRelationshipTypes); const { data: trackedEntityTypeName, isLoading: isLoadingTEType } = useTrackedEntityTypeName(trackedEntityTypeId); + const { + data: relationships, + isError, + isLoading: isLoadingRelationships, + } = useRelationships({ + entityId: teiId, + searchMode: RelationshipSearchEntities.TRACKED_ENTITY, + relationshipTypes, + }); const isLoading = useMemo(() => isLoadingRelationships || isLoadingTEType, [isLoadingRelationships, isLoadingTEType], @@ -36,6 +46,10 @@ export const WidgetTrackedEntityRelationship = ({ ); } + if (!relationshipTypes?.length) { + return null; + } + return ( - { - relationshipTypes => ( - - ) - } + ); }; diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/RelationshipsWidget.component.js b/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/RelationshipsWidget.component.js index c0ee94c29d..0eb6b9a6d2 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/RelationshipsWidget.component.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/RelationshipsWidget.component.js @@ -4,7 +4,6 @@ import { Chip, IconLink24, spacers } from '@dhis2/ui'; import { withStyles } from '@material-ui/core'; import { Widget } from '../../../Widget'; import { useGroupedLinkedEntities } from './useGroupedLinkedEntities'; -import { useRelationshipTypes } from './useRelationshipTypes'; import { LinkedEntitiesViewer } from './LinkedEntitiesViewer.component'; import type { Props, StyledProps } from './relationshipsWidget.types'; import { LoadingMaskElementCenter } from '../../../LoadingMasks'; @@ -23,14 +22,13 @@ const RelationshipsWidgetPlain = ({ title, relationships, isLoading, - cachedRelationshipTypes, sourceId, + relationshipTypes, onLinkedRecordClick, children, classes, }: StyledProps) => { const [open, setOpenStatus] = useState(true); - const { data: relationshipTypes } = useRelationshipTypes(cachedRelationshipTypes); const groupedLinkedEntities = useGroupedLinkedEntities(sourceId, relationshipTypes, relationships); if (isLoading) { @@ -83,9 +81,8 @@ const RelationshipsWidgetPlain = ({ onLinkedRecordClick={onLinkedRecordClick} /> ) - }{ - relationshipTypes && children(relationshipTypes) } + {children}
); diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/relationshipsWidget.types.js b/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/relationshipsWidget.types.js index e7e8d306c3..7dce149334 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/relationshipsWidget.types.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/relationshipsWidget.types.js @@ -6,11 +6,11 @@ import type { LinkedRecordClick } from './types'; export type Props = $ReadOnly<{| title: string, relationships?: Array, - cachedRelationshipTypes?: RelationshipTypes, + relationshipTypes: RelationshipTypes, isLoading: boolean, sourceId: string, onLinkedRecordClick: LinkedRecordClick, - children: (relationshipTypes: RelationshipTypes) => Node, + children: Node, |}>; export type StyledProps = $ReadOnly<{| diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/useGroupedLinkedEntities.js b/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/useGroupedLinkedEntities.js index d339202c7b..095f8e5c8a 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/useGroupedLinkedEntities.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/common/RelationshipsWidget/useGroupedLinkedEntities.js @@ -8,7 +8,7 @@ import { dataElementTypes } from '../../../../metaData'; import { RELATIONSHIP_ENTITIES } from '../constants'; import { convertClientToList, convertServerToClient } from '../../../../converters'; import type { GroupedLinkedEntities, LinkedEntityData } from './types'; -import type { InputRelationshipData, RelationshipTypes } from '../Types'; +import type { ApiLinkedEntity, InputRelationshipData, RelationshipTypes } from '../Types'; const getFallbackFieldsByRelationshipEntity = { @@ -137,18 +137,19 @@ const getLinkedEntityData = (apiLinkedEntity, relationshipCreatedAt, pendingApiR return null; }; -const determineLinkedEntity = (fromEntity, toEntity, sourceId) => { - if (fromEntity.trackedEntity?.trackedEntity === sourceId || fromEntity.event?.event === sourceId) { - return toEntity; - } +export const determineLinkedEntity = + (fromEntity: ApiLinkedEntity, toEntity: ApiLinkedEntity, sourceId: string): ApiLinkedEntity | null => { + if (fromEntity.trackedEntity?.trackedEntity === sourceId || fromEntity.event?.event === sourceId) { + return toEntity; + } - if (toEntity.trackedEntity?.trackedEntity === sourceId || toEntity.event?.event === sourceId) { - return fromEntity; - } + if (toEntity.trackedEntity?.trackedEntity === sourceId || toEntity.event?.event === sourceId) { + return fromEntity; + } - log.error(errorCreator('Could not determine linked entity')({ fromEntity, toEntity, sourceId })); - return null; -}; + log.error(errorCreator('Could not determine linked entity')({ fromEntity, toEntity, sourceId })); + return null; + }; export const useGroupedLinkedEntities = ( sourceId: string, @@ -184,6 +185,10 @@ export const useGroupedLinkedEntities = ( return accGroupedLinkedEntities; } + if (!relationshipType.bidirectional && apiLinkedEntity === fromEntity) { + return accGroupedLinkedEntities; + } + const linkedEntityData = getLinkedEntityData(apiLinkedEntity, relationshipCreatedAt, pendingApiResponse); if (!linkedEntityData) { return accGroupedLinkedEntities; diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js b/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js index 9c5b323232..7f626a84c1 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js @@ -1,7 +1,8 @@ // @flow import { useMemo } from 'react'; import { useApiDataQuery } from '../../../../utils/reactQueryHelpers'; -import type { InputRelationshipData } from '../Types'; +import type { InputRelationshipData, RelationshipTypes } from '../Types'; +import { determineLinkedEntity } from '../RelationshipsWidget/useGroupedLinkedEntities'; export const RelationshipSearchEntities = Object.freeze({ TRACKED_ENTITY: 'trackedEntity', @@ -9,12 +10,19 @@ export const RelationshipSearchEntities = Object.freeze({ EVENT: 'event', }); +type Props = {| + entityId: string, + searchMode: $Values, + relationshipTypes: ?RelationshipTypes, +|} + type ReturnData = Array; -export const useRelationships = (entityId: string, searchMode: string) => { +export const useRelationships = ({ entityId, searchMode, relationshipTypes }: Props) => { const query = useMemo(() => ({ resource: 'tracker/relationships', params: { + // $FlowFixMe - searchMode should be a valid key of RelationshipSearchEntities [searchMode]: entityId, fields: 'relationshipType,createdAt,from[trackedEntity[trackedEntity,attributes,program,orgUnit,trackedEntityType],event[event,dataValues,program,orgUnit,orgUnitName,status,createdAt]],to[trackedEntity[trackedEntity,attributes,program,orgUnit,trackedEntityType],event[event,dataValues,program,orgUnit,orgUnitName,status,createdAt]]', }, @@ -25,7 +33,32 @@ export const useRelationships = (entityId: string, searchMode: string) => { query, { enabled: !!entityId, - select: ({ instances }: any) => instances, + select: ({ instances }: any) => { + if (!relationshipTypes?.length || !instances?.length) { + return []; + } + + return instances.reduce((acc, relationship) => { + const relationshipType = relationshipTypes + .find(relType => relType.id === relationship.relationshipType); + if (!relationshipType) { + return acc; + } + const { from, to } = relationship; + const apiLinkedEntity = determineLinkedEntity(from, to, entityId); + + if (!apiLinkedEntity) { + return acc; + } + + if (!relationshipType.bidirectional && apiLinkedEntity === from) { + return acc; + } + + acc.push(relationship); + return acc; + }, []); + }, }, ); }; From 52410e597496e7e8a20696bc12a5b3cc69c83033 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Thu, 14 Dec 2023 14:13:24 +0000 Subject: [PATCH 20/32] chore(release): cut 100.47.3 [skip release] ## [100.47.3](https://github.com/dhis2/capture-app/compare/v100.47.2...v100.47.3) (2023-12-14) ### Bug Fixes * [DHIS2-16084] Filter unidirectional relationship types ([#3477](https://github.com/dhis2/capture-app/issues/3477)) ([3579fc0](https://github.com/dhis2/capture-app/commit/3579fc05d02f6210f381f93414d07b60a0cfea53)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d367c7378..a7fbd05529 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [100.47.3](https://github.com/dhis2/capture-app/compare/v100.47.2...v100.47.3) (2023-12-14) + + +### Bug Fixes + +* [DHIS2-16084] Filter unidirectional relationship types ([#3477](https://github.com/dhis2/capture-app/issues/3477)) ([3579fc0](https://github.com/dhis2/capture-app/commit/3579fc05d02f6210f381f93414d07b60a0cfea53)) + ## [100.47.2](https://github.com/dhis2/capture-app/compare/v100.47.1...v100.47.2) (2023-12-10) diff --git a/package.json b/package.json index 2a9f6bfdf8..d01e5c21bf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.47.2", + "version": "100.47.3", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.47.2", + "@dhis2/rules-engine-javascript": "100.47.3", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index ae68b52d3a..162fc299cf 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.47.2", + "version": "100.47.3", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From 6263aa8a2114b028afff3b78c39f699c0946e682 Mon Sep 17 00:00:00 2001 From: eirikhaugstulen Date: Fri, 15 Dec 2023 15:01:50 +0100 Subject: [PATCH 21/32] feat: [DHIS2-15783] Tooltip on long working list names (#3474) --- .../DataEntry/withMainButton.js | 2 +- .../FilterButtonMain.component.js | 2 +- .../components/Notes/Notes.component.js | 2 +- .../QuickActionButton/QuickActionButton.js | 2 +- .../ProgramStageSelector.component.js | 2 +- .../EventDetailsSection.component.js | 2 +- .../Relationships/Relationships.component.js | 2 +- .../TemplateSelector.component.js | 6 +- .../TemplateSelectorChip.component.js | 22 ++++++- .../ConditionalTooltip.component.js | 0 .../ConditionalTooltip/index.js | 0 .../TooltipForChip.component.js | 60 +++++++++++++++++++ .../Tooltips/TooltipForChip/index.js | 2 + .../Actions/AddNew/AddNew.component.js | 2 +- .../DataEntry/withMainButton.js | 2 +- .../WidgetEventEdit.container.js | 2 +- .../Stages/Stage/Stage.component.js | 2 +- .../StageDetail/StageDetail.component.js | 2 +- .../TemplateSelectorChip.component.js | 41 +++++++++---- .../TemplateSelectorChipContent.component.js | 4 +- 20 files changed, 131 insertions(+), 28 deletions(-) rename src/core_modules/capture-core/components/{ => Tooltips}/ConditionalTooltip/ConditionalTooltip.component.js (100%) rename src/core_modules/capture-core/components/{ => Tooltips}/ConditionalTooltip/index.js (100%) create mode 100644 src/core_modules/capture-core/components/Tooltips/TooltipForChip/TooltipForChip.component.js create mode 100644 src/core_modules/capture-core/components/Tooltips/TooltipForChip/index.js diff --git a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/DataEntry/withMainButton.js b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/DataEntry/withMainButton.js index 8b18d2f201..66f2be3f12 100644 --- a/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/DataEntry/withMainButton.js +++ b/src/core_modules/capture-core/components/DataEntries/SingleEventRegistrationEntry/DataEntryWrapper/DataEntry/withMainButton.js @@ -3,7 +3,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import i18n from '@dhis2/d2-i18n'; import { Button } from '@dhis2/ui'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import { newEventSaveTypes } from './newEventSaveTypes'; import { getDataEntryKey } from '../../../../DataEntry/common/getDataEntryKey'; import { type RenderFoundation } from '../../../../../metaData'; diff --git a/src/core_modules/capture-core/components/ListView/Filters/FilterButton/FilterButtonMain.component.js b/src/core_modules/capture-core/components/ListView/Filters/FilterButton/FilterButtonMain.component.js index 6541747f96..8a1c83ddd1 100644 --- a/src/core_modules/capture-core/components/ListView/Filters/FilterButton/FilterButtonMain.component.js +++ b/src/core_modules/capture-core/components/ListView/Filters/FilterButton/FilterButtonMain.component.js @@ -3,7 +3,7 @@ import React, { Component } from 'react'; import { withStyles } from '@material-ui/core/styles'; import Popover from '@material-ui/core/Popover'; import { IconChevronDown16, IconChevronUp16, Button } from '@dhis2/ui'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import { ActiveFilterButton } from './ActiveFilterButton.component'; import { FilterSelectorContents } from '../Contents'; import type { UpdateFilter, ClearFilter, RemoveFilter } from '../../types'; diff --git a/src/core_modules/capture-core/components/Notes/Notes.component.js b/src/core_modules/capture-core/components/Notes/Notes.component.js index bb1fc61c8d..1a7626bfd7 100644 --- a/src/core_modules/capture-core/components/Notes/Notes.component.js +++ b/src/core_modules/capture-core/components/Notes/Notes.component.js @@ -6,7 +6,7 @@ import { withStyles } from '@material-ui/core'; import { colors, spacersNum, Menu, MenuItem, Button } from '@dhis2/ui'; import i18n from '@dhis2/d2-i18n'; import { withFocusSaver } from 'capture-ui'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import { TextField } from '../FormFields/New'; import type { Note } from './notes.types'; diff --git a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentQuickActions/QuickActionButton/QuickActionButton.js b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentQuickActions/QuickActionButton/QuickActionButton.js index 7727a05019..ae60c51371 100644 --- a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentQuickActions/QuickActionButton/QuickActionButton.js +++ b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/EnrollmentQuickActions/QuickActionButton/QuickActionButton.js @@ -3,7 +3,7 @@ import React from 'react'; import i18n from '@dhis2/d2-i18n'; import { Button, spacers } from '@dhis2/ui'; import { withStyles } from '@material-ui/core'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import type { QuickActionButtonTypes } from './QuickActionButton.types'; const styles = { diff --git a/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/ProgramStageSelector/ProgramStageSelector.component.js b/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/ProgramStageSelector/ProgramStageSelector.component.js index 092ddf13f6..01967b1f21 100644 --- a/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/ProgramStageSelector/ProgramStageSelector.component.js +++ b/src/core_modules/capture-core/components/Pages/EnrollmentAddEvent/ProgramStageSelector/ProgramStageSelector.component.js @@ -2,7 +2,7 @@ import React from 'react'; import i18n from '@dhis2/d2-i18n'; import { Button, spacers, spacersNum } from '@dhis2/ui'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import { withStyles } from '@material-ui/core'; import { NonBundledDhis2Icon } from '../../../NonBundledDhis2Icon'; diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/EventDetailsSection/EventDetailsSection.component.js b/src/core_modules/capture-core/components/Pages/ViewEvent/EventDetailsSection/EventDetailsSection.component.js index 31da7bdbd4..7f6a2a440f 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/EventDetailsSection/EventDetailsSection.component.js +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/EventDetailsSection/EventDetailsSection.component.js @@ -5,7 +5,7 @@ import { dataEntryIds, dataEntryKeys } from 'capture-core/constants'; import { withStyles } from '@material-ui/core/'; import { spacers, IconFileDocument24, Button } from '@dhis2/ui'; import i18n from '@dhis2/d2-i18n'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import { ViewEventSection } from '../Section/ViewEventSection.component'; import { ViewEventSectionHeader } from '../Section/ViewEventSectionHeader.component'; import { EditEventDataEntry } from '../../../WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.container'; diff --git a/src/core_modules/capture-core/components/Relationships/Relationships.component.js b/src/core_modules/capture-core/components/Relationships/Relationships.component.js index 1ee7f8af6c..be9fb6c569 100644 --- a/src/core_modules/capture-core/components/Relationships/Relationships.component.js +++ b/src/core_modules/capture-core/components/Relationships/Relationships.component.js @@ -5,7 +5,7 @@ import classNames from 'classnames'; import i18n from '@dhis2/d2-i18n'; import { IconButton, withStyles } from '@material-ui/core'; import { IconArrowRight16, IconCross24, Button } from '@dhis2/ui'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import type { RelationshipType } from '../../metaData'; import type { Relationship, Entity } from './relationships.types'; diff --git a/src/core_modules/capture-core/components/TemplateSelector/TemplateSelector.component.js b/src/core_modules/capture-core/components/TemplateSelector/TemplateSelector.component.js index 5ffa6dd1a8..43a48240be 100644 --- a/src/core_modules/capture-core/components/TemplateSelector/TemplateSelector.component.js +++ b/src/core_modules/capture-core/components/TemplateSelector/TemplateSelector.component.js @@ -18,7 +18,6 @@ const getStyles = () => ({ padding: 0, gap: '4px', marginBottom: spacers.dp8, - overflow: 'hidden', }, chipContainer: { padding: 0, @@ -80,7 +79,10 @@ const TemplateSelectorPlain = (props: Props) => { const { id } = customTemplate; return (
- +
); }); diff --git a/src/core_modules/capture-core/components/TemplateSelector/TemplateSelectorChip.component.js b/src/core_modules/capture-core/components/TemplateSelector/TemplateSelectorChip.component.js index 24e3ddc79f..5b9b05cfb0 100644 --- a/src/core_modules/capture-core/components/TemplateSelector/TemplateSelectorChip.component.js +++ b/src/core_modules/capture-core/components/TemplateSelector/TemplateSelectorChip.component.js @@ -2,6 +2,7 @@ import React, { useCallback } from 'react'; import { Chip } from '@dhis2/ui'; import type { WorkingListTemplate } from './workingListsBase.types'; +import { TooltipForChip } from '../Tooltips/TooltipForChip'; type Props = { template: WorkingListTemplate, @@ -19,8 +20,23 @@ export const TemplateSelectorChip = (props: Props) => { const text = displayName.length > 30 ? `${displayName.substring(0, 27)}...` : displayName; return ( - - {text} - + 30} + onClick={selectTemplateHandler} + > + + {text} + + + ); }; diff --git a/src/core_modules/capture-core/components/ConditionalTooltip/ConditionalTooltip.component.js b/src/core_modules/capture-core/components/Tooltips/ConditionalTooltip/ConditionalTooltip.component.js similarity index 100% rename from src/core_modules/capture-core/components/ConditionalTooltip/ConditionalTooltip.component.js rename to src/core_modules/capture-core/components/Tooltips/ConditionalTooltip/ConditionalTooltip.component.js diff --git a/src/core_modules/capture-core/components/ConditionalTooltip/index.js b/src/core_modules/capture-core/components/Tooltips/ConditionalTooltip/index.js similarity index 100% rename from src/core_modules/capture-core/components/ConditionalTooltip/index.js rename to src/core_modules/capture-core/components/Tooltips/ConditionalTooltip/index.js diff --git a/src/core_modules/capture-core/components/Tooltips/TooltipForChip/TooltipForChip.component.js b/src/core_modules/capture-core/components/Tooltips/TooltipForChip/TooltipForChip.component.js new file mode 100644 index 0000000000..01c539b3af --- /dev/null +++ b/src/core_modules/capture-core/components/Tooltips/TooltipForChip/TooltipForChip.component.js @@ -0,0 +1,60 @@ +// @flow +import React from 'react'; +import { Tooltip } from '@dhis2/ui'; +import { withStyles } from '@material-ui/core/'; + +type Props = { + enabled: boolean, + onClick: Function, + children: any, + ...CssClasses, +}; + +const styles = { + // button style reset + button: { + border: 'none', + backgroundColor: 'transparent', + borderRadius: '16px', + padding: 0, + margin: 0, + minWidth: 0, + minHeight: 0, + '&:hover': { + backgroundColor: 'transparent', + }, + }, +}; +const TooltipForChipPlain = (props: Props) => { + const { enabled, children, classes, onClick, ...passOnProps } = props; + + return enabled ? + ( + + {({ ref, onMouseOver, onMouseOut }) => ( + + )} + + ) : ( + + ); +}; + +export const TooltipForChip = withStyles(styles)(TooltipForChipPlain); diff --git a/src/core_modules/capture-core/components/Tooltips/TooltipForChip/index.js b/src/core_modules/capture-core/components/Tooltips/TooltipForChip/index.js new file mode 100644 index 0000000000..8894bd8888 --- /dev/null +++ b/src/core_modules/capture-core/components/Tooltips/TooltipForChip/index.js @@ -0,0 +1,2 @@ +// @flow +export { TooltipForChip } from './TooltipForChip.component'; diff --git a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/AddNew/AddNew.component.js b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/AddNew/AddNew.component.js index e4ec61be1b..ce6e30b06b 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollment/Actions/AddNew/AddNew.component.js +++ b/src/core_modules/capture-core/components/WidgetEnrollment/Actions/AddNew/AddNew.component.js @@ -2,7 +2,7 @@ import { IconAdd16, MenuItem } from '@dhis2/ui'; import React from 'react'; import i18n from '@dhis2/d2-i18n'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import type { Props } from './addNew.types'; export const AddNew = ({ canAddNew, onlyEnrollOnce, tetName, onAddNew }: Props) => { diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/withMainButton.js b/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/withMainButton.js index 42491ef4ab..ba6088af20 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/withMainButton.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/withMainButton.js @@ -3,7 +3,7 @@ import * as React from 'react'; import { connect } from 'react-redux'; import i18n from '@dhis2/d2-i18n'; import { Button } from '@dhis2/ui'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import { type RenderFoundation } from '../../../metaData'; type Props = { diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/WidgetEventEdit.container.js b/src/core_modules/capture-core/components/WidgetEventEdit/WidgetEventEdit.container.js index e2096656ab..58c4645463 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/WidgetEventEdit.container.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/WidgetEventEdit.container.js @@ -5,7 +5,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { spacersNum, Button, colors, IconEdit24, IconArrowLeft24 } from '@dhis2/ui'; import { withStyles } from '@material-ui/core'; import i18n from '@dhis2/d2-i18n'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import { useEnrollmentEditEventPageMode, useAvailableProgramStages } from 'capture-core/hooks'; import { useCoreOrgUnit } from 'capture-core/metadataRetrieval/coreOrgUnit'; import type { Props } from './widgetEventEdit.types'; diff --git a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/Stage.component.js b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/Stage.component.js index f8a8908b20..77728e6dc8 100644 --- a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/Stage.component.js +++ b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/Stage.component.js @@ -4,7 +4,7 @@ import cx from 'classnames'; import i18n from '@dhis2/d2-i18n'; import { withStyles } from '@material-ui/core'; import { spacersNum, colors, IconAdd16, Button } from '@dhis2/ui'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import { StageOverview } from './StageOverview'; import type { Props } from './stage.types'; import { Widget } from '../../../Widget'; diff --git a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js index 0cc28bc98c..86a4cad8bb 100644 --- a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js +++ b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js @@ -16,7 +16,7 @@ import { colors, IconAdd16, Tooltip, } from '@dhis2/ui'; -import { ConditionalTooltip } from 'capture-core/components/ConditionalTooltip'; +import { ConditionalTooltip } from 'capture-core/components/Tooltips/ConditionalTooltip'; import { sortDataFromEvent } from './hooks/sortFuntions'; import { useComputeDataFromEvent, useComputeHeaderColumn, formatRowForView } from './hooks/useEventList'; import { DEFAULT_NUMBER_OF_ROW, SORT_DIRECTION } from './hooks/constants'; diff --git a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateSelectorChip.component.js b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateSelectorChip.component.js index 5ce7331edf..238423ef2c 100644 --- a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateSelectorChip.component.js +++ b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateSelectorChip.component.js @@ -3,6 +3,7 @@ import * as React from 'react'; import { Chip } from '@dhis2/ui'; import { TemplateSelectorChipContent } from './TemplateSelectorChipContent.component'; import type { WorkingListTemplate } from './workingListsBase.types'; +import { TooltipForChip } from '../../Tooltips/TooltipForChip'; type PassOnProps = { currentListIsModified: boolean, @@ -13,10 +14,17 @@ type Props = { template: WorkingListTemplate, currentTemplateId: string, onSelectTemplate: Function, + maxCharacters?: number, }; export const TemplateSelectorChip = (props: Props) => { - const { template, currentTemplateId, onSelectTemplate, ...passOnProps } = props; + const { + template, + currentTemplateId, + onSelectTemplate, + maxCharacters = 30, + ...passOnProps + } = props; const { name, id } = template; const selectTemplateHandler = React.useCallback(() => { @@ -27,16 +35,29 @@ export const TemplateSelectorChip = (props: Props) => { ]); return ( - maxCharacters} onClick={selectTemplateHandler} > - - + + + + ); }; + diff --git a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateSelectorChipContent.component.js b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateSelectorChipContent.component.js index 57d0c53205..d9efe28079 100644 --- a/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateSelectorChipContent.component.js +++ b/src/core_modules/capture-core/components/WorkingLists/WorkingListsBase/TemplateSelectorChipContent.component.js @@ -2,6 +2,7 @@ type Props = { currentListIsModified: boolean, + maxCharacters: number, text: string, isSelectedTemplate: boolean, }; @@ -10,10 +11,11 @@ export const TemplateSelectorChipContent = (props: Props) => { const { currentListIsModified, text, + maxCharacters, isSelectedTemplate, } = props; - const truncatedText = text.length > 30 ? `${text.substring(0, 27)}...` : text; + const truncatedText = text.length > maxCharacters ? `${text.substring(0, maxCharacters - 3)}...` : text; const content = isSelectedTemplate && currentListIsModified ? `${truncatedText} *` : truncatedText; return content; From 4935fa0774cd9eee1f307b4ce53f4b3e2a3f9541 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Fri, 15 Dec 2023 14:09:29 +0000 Subject: [PATCH 22/32] chore(release): cut 100.48.0 [skip release] # [100.48.0](https://github.com/dhis2/capture-app/compare/v100.47.3...v100.48.0) (2023-12-15) ### Features * [DHIS2-15783] Tooltip on long working list names ([#3474](https://github.com/dhis2/capture-app/issues/3474)) ([6263aa8](https://github.com/dhis2/capture-app/commit/6263aa8a2114b028afff3b78c39f699c0946e682)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7fbd05529..cd38f74016 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [100.48.0](https://github.com/dhis2/capture-app/compare/v100.47.3...v100.48.0) (2023-12-15) + + +### Features + +* [DHIS2-15783] Tooltip on long working list names ([#3474](https://github.com/dhis2/capture-app/issues/3474)) ([6263aa8](https://github.com/dhis2/capture-app/commit/6263aa8a2114b028afff3b78c39f699c0946e682)) + ## [100.47.3](https://github.com/dhis2/capture-app/compare/v100.47.2...v100.47.3) (2023-12-14) diff --git a/package.json b/package.json index d01e5c21bf..27f8075d67 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.47.3", + "version": "100.48.0", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.47.3", + "@dhis2/rules-engine-javascript": "100.48.0", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index 162fc299cf..dbdc80d2d0 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.47.3", + "version": "100.48.0", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From 2a6d4a839ae0daed7b2ddbf09a401c29dbb3cfd7 Mon Sep 17 00:00:00 2001 From: eirikhaugstulen Date: Mon, 18 Dec 2023 14:32:39 +0100 Subject: [PATCH 23/32] feat: [DHIS2-12544] Add verbose logging to rules engine (#3480) --- packages/rules-engine/src/RulesEngine.js | 22 ++++++++ .../rules-engine/src/rulesEngine.types.js | 2 +- .../expressionService/executeExpression.js | 6 +++ .../executeExpression.types.js | 4 +- src/components/App/App.component.js | 10 +++- src/components/App/AppContents.component.js | 4 +- .../RulesEngineVerboseInitializer.js | 11 ++++ .../RulesEngineVerboseInitializer/index.js | 2 + .../rules/__tests__/rulesEngine.test.js | 50 +++++++++++++++++++ .../capture-core/rules/rulesEngine.js | 7 ++- .../capture-core/rules/useRuleEngineFlags.js | 23 +++++++++ 11 files changed, 134 insertions(+), 7 deletions(-) create mode 100644 src/core_modules/capture-core/components/RulesEngineVerboseInitializer/RulesEngineVerboseInitializer.js create mode 100644 src/core_modules/capture-core/components/RulesEngineVerboseInitializer/index.js create mode 100644 src/core_modules/capture-core/rules/useRuleEngineFlags.js diff --git a/packages/rules-engine/src/RulesEngine.js b/packages/rules-engine/src/RulesEngine.js index d634f5d558..7b70025632 100644 --- a/packages/rules-engine/src/RulesEngine.js +++ b/packages/rules-engine/src/RulesEngine.js @@ -10,6 +10,7 @@ import type { IConvertInputRulesValue, IConvertOutputRulesEffectsValue, IDateUtils, + Flag, } from './rulesEngine.types'; import { getRulesEffectsProcessor } from './processors/rulesEffectsProcessor/rulesEffectsProcessor'; import { effectActions, typeof environmentTypes } from './constants'; @@ -21,18 +22,21 @@ export class RulesEngine { variableService: VariableService; dateUtils: IDateUtils; userRoles: Array; + flags: Flag; constructor( inputConverter: IConvertInputRulesValue, outputConverter: IConvertOutputRulesEffectsValue, dateUtils: IDateUtils, environment: $Values, + flags?: Flag, ) { this.inputConverter = inputConverter; this.outputConverter = outputConverter; this.valueProcessor = new ValueProcessor(inputConverter); this.variableService = new VariableService(this.valueProcessor.processValue, dateUtils, environment); this.dateUtils = dateUtils; + this.flags = flags ?? {}; } /** @@ -114,10 +118,15 @@ export class RulesEngine { expression, dhisFunctions, variablesHash, + flags: this.flags, onError: (error, injectedExpression) => log.warn( `Expression with id rule:${rule.id} could not be run. ` + `Original condition was: ${expression} - ` + `Evaluation ended up as:${injectedExpression} - error message:${error}`), + onVerboseLog: injectedExpression => console.log( + `Expression with id rule:${rule.id} was run. ` + + `Original condition was: ${expression} - ` + + `Evaluation ended up as:${injectedExpression}`), }); } else { log.warn(`Rule id:'${rule.id}' and name:'${rule.displayName}' ` + @@ -149,10 +158,15 @@ export class RulesEngine { expression: actionExpression, dhisFunctions, variablesHash, + flags: this.flags, onError: (error, injectedExpression) => log.warn( `Expression with id rule: action:${id} could not be run. ` + `Original condition was: ${actionExpression} - ` + `Evaluation ended up as:${injectedExpression} - error message:${error}`), + onVerboseLog: injectedExpression => log.info( + `Expression with id rule: action:${id} was run. ` + + `Original condition was: ${actionExpression} - ` + + `Evaluation ended up as: ${injectedExpression}`), }); } @@ -196,4 +210,12 @@ export class RulesEngine { setSelectedUserRoles(userRoles: Array) { this.userRoles = userRoles; } + + setFlags(flags: Flag) { + this.flags = flags; + } + + getFlags(): Flag { + return this.flags; + } } diff --git a/packages/rules-engine/src/rulesEngine.types.js b/packages/rules-engine/src/rulesEngine.types.js index 3f1d422303..59b2fc9b62 100644 --- a/packages/rules-engine/src/rulesEngine.types.js +++ b/packages/rules-engine/src/rulesEngine.types.js @@ -230,5 +230,5 @@ export type IConvertOutputRulesEffectsValue = {| |}; export type Flag = { - debug: boolean + verbose: boolean, } diff --git a/packages/rules-engine/src/services/expressionService/executeExpression.js b/packages/rules-engine/src/services/expressionService/executeExpression.js index 3e7c9c3256..470105f032 100644 --- a/packages/rules-engine/src/services/expressionService/executeExpression.js +++ b/packages/rules-engine/src/services/expressionService/executeExpression.js @@ -177,7 +177,9 @@ export const executeExpression = ({ expression, dhisFunctions, variablesHash, + flags = {}, onError, + onVerboseLog, }: ExecuteExpressionInput) => { const expressionWithInjectedVariableValues = injectVariableValues(expression, variablesHash); @@ -191,6 +193,10 @@ export const executeExpression = ({ removeNewLinesFromNonStrings(expressionWithInjectedVariableValues, expressionModuloStrings), onError, ); + + if (flags.verbose) { + onVerboseLog(expressionWithInjectedVariableValues); + } } catch (error) { onError(error.message, expressionWithInjectedVariableValues); } diff --git a/packages/rules-engine/src/services/expressionService/executeExpression.types.js b/packages/rules-engine/src/services/expressionService/executeExpression.types.js index ba88c7ed53..d680758864 100644 --- a/packages/rules-engine/src/services/expressionService/executeExpression.types.js +++ b/packages/rules-engine/src/services/expressionService/executeExpression.types.js @@ -1,5 +1,5 @@ // @flow -import type { RuleVariables } from '../../rulesEngine.types'; +import type { Flag, RuleVariables } from '../../rulesEngine.types'; import type { D2Functions, D2FunctionConfig } from '../../d2Functions'; export type ExpressionSet = $ReadOnly<{| @@ -23,5 +23,7 @@ export type ExecuteExpressionInput = $ReadOnly<{| expression: string, dhisFunctions: D2Functions, variablesHash: RuleVariables, + flags?: Flag, onError: ErrorHandler, + onVerboseLog: (expressionWithInjectedVariableValues: string) => void, |}>; diff --git a/src/components/App/App.component.js b/src/components/App/App.component.js index 694e2b1379..949eb69f6c 100644 --- a/src/components/App/App.component.js +++ b/src/components/App/App.component.js @@ -1,10 +1,14 @@ // @flow /* eslint-disable import/first */ import './app.css'; -import * as React from 'react'; +import React from 'react'; import { Provider } from 'react-redux'; import D2UIApp from '@dhis2/d2-ui-app'; import { AppContents } from './AppContents.component'; +import { + RulesEngineVerboseInitializer, +} from '../../core_modules/capture-core/components/RulesEngineVerboseInitializer'; + type Props = { store: ReduxStore, @@ -16,7 +20,9 @@ export const App = ({ store }: Props) => ( store={store} > - + + +
diff --git a/src/components/App/AppContents.component.js b/src/components/App/AppContents.component.js index 6839da4d41..b476d02f5a 100644 --- a/src/components/App/AppContents.component.js +++ b/src/components/App/AppContents.component.js @@ -1,6 +1,6 @@ // @flow -import React from 'react'; +import React, { memo } from 'react'; import { withStyles } from '@material-ui/core/styles'; import { systemSettingsStore } from 'capture-core/metaDataMemoryStores'; import { FeedbackBar } from 'capture-core/components/FeedbackBar'; @@ -30,4 +30,4 @@ const Index = ({ classes }: Props) => ( ); Index.displayName = 'AppContents'; -export const AppContents = withStyles(getStyles)(Index); +export const AppContents = withStyles(getStyles)(memo(Index)); diff --git a/src/core_modules/capture-core/components/RulesEngineVerboseInitializer/RulesEngineVerboseInitializer.js b/src/core_modules/capture-core/components/RulesEngineVerboseInitializer/RulesEngineVerboseInitializer.js new file mode 100644 index 0000000000..6ed402f545 --- /dev/null +++ b/src/core_modules/capture-core/components/RulesEngineVerboseInitializer/RulesEngineVerboseInitializer.js @@ -0,0 +1,11 @@ +// @flow +import { useRuleEngineFlags } from '../../rules/useRuleEngineFlags'; + +type Props = {| + children: React$Node, +|}; +export const RulesEngineVerboseInitializer = ({ children }: Props) => { + useRuleEngineFlags(); + + return children; +}; diff --git a/src/core_modules/capture-core/components/RulesEngineVerboseInitializer/index.js b/src/core_modules/capture-core/components/RulesEngineVerboseInitializer/index.js new file mode 100644 index 0000000000..5043a09470 --- /dev/null +++ b/src/core_modules/capture-core/components/RulesEngineVerboseInitializer/index.js @@ -0,0 +1,2 @@ +// @flow +export { RulesEngineVerboseInitializer } from './RulesEngineVerboseInitializer'; diff --git a/src/core_modules/capture-core/rules/__tests__/rulesEngine.test.js b/src/core_modules/capture-core/rules/__tests__/rulesEngine.test.js index 4a0f04e813..9aebeadd75 100644 --- a/src/core_modules/capture-core/rules/__tests__/rulesEngine.test.js +++ b/src/core_modules/capture-core/rules/__tests__/rulesEngine.test.js @@ -225,6 +225,56 @@ describe('Rules engine', () => { // then expect(rulesEffects).toEqual([]); }); + + test('The rules engine can enable verbose logging', () => { + // When + rulesEngine.setFlags({ verbose: true }); + + // Then + expect(rulesEngine.getFlags()).toEqual({ verbose: true }); + }); + + test('Rules are calculated when verbose is set', () => { + const programRules = [ + { + id: 'GC4gpdoSD4r', + condition: 'true', + description: 'Show error if hemoglobin is dangerously low', + displayName: 'Hemoglobin error', + programId: 'lxAQ7Zs9VYR', + programRuleActions: [ + { + id: 'SWfdB5lX0fk', + content: 'Hemoglobin value lower than normal', + displayContent: 'Hemoglobin value lower than normal', + programRuleActionType: 'SHOWERROR', + }, + ], + }, + ]; + + // When + rulesEngine.setFlags({ verbose: true }); + const rulesEffects = rulesEngine.getProgramRuleEffects({ + programRulesContainer: { programRuleVariables, programRules, constants }, + currentEvent, + dataElements: dataElementsInProgram, + selectedOrgUnit: orgUnit, + optionSets, + }); + + // then + expect(rulesEffects).toEqual([ + { + id: 'general', + type: 'SHOWERROR', + error: { + id: 'SWfdB5lX0fk', + message: 'Hemoglobin value lower than normal ', + }, + }, + ]); + }); }); describe('Program Rule Variables corner cases', () => { diff --git a/src/core_modules/capture-core/rules/rulesEngine.js b/src/core_modules/capture-core/rules/rulesEngine.js index 06983888c3..dc91f9f957 100644 --- a/src/core_modules/capture-core/rules/rulesEngine.js +++ b/src/core_modules/capture-core/rules/rulesEngine.js @@ -6,4 +6,9 @@ import { dateUtils, } from './converters'; -export const rulesEngine = new RulesEngine(inputConverter, outputConverter, dateUtils, environmentTypes.WebClient); +export const rulesEngine = new RulesEngine( + inputConverter, + outputConverter, + dateUtils, + environmentTypes.WebClient, +); diff --git a/src/core_modules/capture-core/rules/useRuleEngineFlags.js b/src/core_modules/capture-core/rules/useRuleEngineFlags.js new file mode 100644 index 0000000000..ee6cd84c40 --- /dev/null +++ b/src/core_modules/capture-core/rules/useRuleEngineFlags.js @@ -0,0 +1,23 @@ +// @flow +import { useLayoutEffect } from 'react'; +import { useLocationQuery } from '../utils/routing'; +import { rulesEngine } from './rulesEngine'; + +export const useRuleEngineFlags = () => { + // This hook is used to set the verbose flag on the rules engine + // based on the verbose query param in the URL + + const { verbose } = useLocationQuery(); + + const updateFlags = (flags) => { + rulesEngine.setFlags({ ...rulesEngine.getFlags(), ...flags }); + }; + + useLayoutEffect(() => { + if (verbose === 'true') { + updateFlags({ verbose: true }); + } else { + updateFlags({ verbose: false }); + } + }, [verbose]); +}; From 8abdca3ef63fdf6dd0f96d13c21aa15d7dec6f7e Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Mon, 18 Dec 2023 13:42:02 +0000 Subject: [PATCH 24/32] chore(release): cut 100.49.0 [skip release] # [100.49.0](https://github.com/dhis2/capture-app/compare/v100.48.0...v100.49.0) (2023-12-18) ### Features * [DHIS2-12544] Add verbose logging to rules engine ([#3480](https://github.com/dhis2/capture-app/issues/3480)) ([2a6d4a8](https://github.com/dhis2/capture-app/commit/2a6d4a839ae0daed7b2ddbf09a401c29dbb3cfd7)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd38f74016..d9f2945b4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [100.49.0](https://github.com/dhis2/capture-app/compare/v100.48.0...v100.49.0) (2023-12-18) + + +### Features + +* [DHIS2-12544] Add verbose logging to rules engine ([#3480](https://github.com/dhis2/capture-app/issues/3480)) ([2a6d4a8](https://github.com/dhis2/capture-app/commit/2a6d4a839ae0daed7b2ddbf09a401c29dbb3cfd7)) + # [100.48.0](https://github.com/dhis2/capture-app/compare/v100.47.3...v100.48.0) (2023-12-15) diff --git a/package.json b/package.json index 27f8075d67..8220158c9b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.48.0", + "version": "100.49.0", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.48.0", + "@dhis2/rules-engine-javascript": "100.49.0", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index dbdc80d2d0..d883e1427b 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.48.0", + "version": "100.49.0", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From 44fb2bedf0e2f9d394c58d5a588087cff2c8fa3c Mon Sep 17 00:00:00 2001 From: Tony Valle <79843014+superskip@users.noreply.github.com> Date: Mon, 18 Dec 2023 15:22:05 +0100 Subject: [PATCH 25/32] feat: [DHIS-11419] display assigned users on events in enrollment overview page (#3453) --- .../hooks/useProgramMetadata.js | 113 ++++++++++++++---- .../hooks/useProgramStages.js | 3 +- .../Stages/Stage/Stage.component.js | 3 +- .../StageDetail/StageDetail.component.js | 3 +- .../Stage/StageDetail/hooks/useEventList.js | 11 +- .../Stage/StageDetail/stageDetail.types.js | 1 + .../types/common.types.js | 1 + .../capture-core/converters/serverToClient.js | 10 ++ .../mainEventClientToServerConverter.js | 4 +- .../useDataElementsFromIndexedDB.js | 32 +++++ .../useOptionSetsFromIndexedDB.js | 32 +++++ .../useProgramFromIndexedDB.js | 4 +- .../query/useMetadataQuery.js | 4 +- .../reactQueryHelpers.const.js | 2 +- 14 files changed, 188 insertions(+), 35 deletions(-) create mode 100644 src/core_modules/capture-core/utils/cachedDataHooks/useDataElementsFromIndexedDB.js create mode 100644 src/core_modules/capture-core/utils/cachedDataHooks/useOptionSetsFromIndexedDB.js diff --git a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/hooks/useProgramMetadata.js b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/hooks/useProgramMetadata.js index d319df06d1..542e07dfe6 100644 --- a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/hooks/useProgramMetadata.js +++ b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/hooks/useProgramMetadata.js @@ -1,28 +1,99 @@ // @flow -import { useEffect } from 'react'; -import { useDataQuery } from '@dhis2/app-runtime'; - -const query = { - programData: { - resource: 'programs', - id: ({ id }) => id, - params: { - fields: - ['programStages[id,repeatable,hideDueDate,programStageDataElements[displayInReports,dataElement[id,valueType,displayName,displayFormName,optionSet[options[code,name]]]'], - }, - }, -}; +import { useMemo } from 'react'; +import { useProgramFromIndexedDB } from '../../../../../utils/cachedDataHooks/useProgramFromIndexedDB'; +import { useDataElementsFromIndexedDB } from '../../../../../utils/cachedDataHooks/useDataElementsFromIndexedDB'; +import { useOptionSetsFromIndexedDB } from '../../../../../utils/cachedDataHooks/useOptionSetsFromIndexedDB'; + +const queryKey = 'useProgramMetadata'; export const useProgramMetadata = (programId: string) => { - const { data, error, loading, refetch } = useDataQuery(query, { - lazy: true, - }); + const { program, isLoading, isError } = useProgramFromIndexedDB(programId, { enabled: !!programId }); + + const dataElementIds = useMemo(() => + (program ? program.programStages.reduce( + (acc, stage) => stage.programStageDataElements.reduce( + (accIds, dataElement) => { + accIds.add(dataElement.dataElementId); + return accIds; + }, acc), + new Set) : undefined), [program]); + + const { + isLoading: loadingDataElements, + dataElements, + isError: dataElementsError, + } = useDataElementsFromIndexedDB([queryKey, programId], dataElementIds); + + const derivedDataElementValues = useMemo(() => + (dataElements ? ({ + optionSetIds: dataElements.reduce((acc, dataElement) => { + if (dataElement.optionSetValue) { + acc.add(dataElement.optionSet.id); + } + return acc; + }, new Set), + dataElementDictionary: dataElements.reduce((acc, dataElement) => { + acc[dataElement.id] = dataElement; + return acc; + }, {}), + }) : undefined), [dataElements]); - useEffect(() => { - if (programId) { - refetch({ id: programId }); + const { + isLoading: loadingOptionSets, + optionSets, + isError: optionSetsError, + } = useOptionSetsFromIndexedDB([queryKey, programId], derivedDataElementValues && derivedDataElementValues.optionSetIds); + + const optionSetDictionary = useMemo( + () => (optionSets ? optionSets.reduce( + (acc, optionSet) => { + acc[optionSet.id] = { + optionSet: { + options: optionSet.options.map(option => ({ + name: option.displayName, + code: option.code, + })), + }, + }; + return acc; + }, {}) : undefined), + [optionSets], + ); + + const programMetadata = useMemo(() => { + if (!program || !derivedDataElementValues || !optionSetDictionary) { + return undefined; } - }, [refetch, programId]); - return { error, programMetadata: !loading && data?.programData ? data.programData : undefined }; + const dataElementDictionary = derivedDataElementValues.dataElementDictionary; + + return { + programStages: program.programStages.map(stage => ({ + id: stage.id, + repeatable: stage.repeatable, + hideDueDate: stage.hideDueDate, + enableUserAssignment: stage.enableUserAssignment, + programStageDataElements: stage.programStageDataElements + .map((programStageDataElement) => { + const dataElement = dataElementDictionary[programStageDataElement.dataElementId]; + return { + displayInReports: programStageDataElement.displayInReports, + dataElement: { + id: dataElement.id, + valueType: dataElement.valueType, + displayName: dataElement.displayName, + displayFormName: dataElement.displayFormName, + optionSet: dataElement.optionSetValue ? optionSetDictionary[dataElement.optionSet.id] : {}, + }, + }; + }), + })), + }; + }, [program, derivedDataElementValues, optionSetDictionary]); + + + return { + error: (isError || dataElementsError || optionSetsError) && { programId }, + programMetadata: (isLoading || loadingDataElements || loadingOptionSets) ? undefined : programMetadata, + }; }; diff --git a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/hooks/useProgramStages.js b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/hooks/useProgramStages.js index 7d692e9867..a746dfe9e6 100644 --- a/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/hooks/useProgramStages.js +++ b/src/core_modules/capture-core/components/Pages/Enrollment/EnrollmentPageDefault/hooks/useProgramStages.js @@ -11,7 +11,7 @@ export const useProgramStages = (program: Program, programStages?: Array { const { id, name, icon, stageForm } = item; - const { hideDueDate, programStageDataElements, repeatable } = programStages.find(p => p.id === id) || {}; + const { hideDueDate, programStageDataElements, repeatable, enableUserAssignment } = programStages.find(p => p.id === id) || {}; if (!programStageDataElements) { log.error(errorCreator(i18n.t('Program stage not found'))(id)); } else { @@ -21,6 +21,7 @@ export const useProgramStages = (program: Program, programStages?: Array { const { displayInReports, dataElement } = currentStageData; diff --git a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/Stage.component.js b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/Stage.component.js index 77728e6dc8..87815c565c 100644 --- a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/Stage.component.js +++ b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/Stage.component.js @@ -30,7 +30,7 @@ const hideProgramStage = (ruleEffects, stageId) => ( export const StagePlain = ({ stage, events, classes, className, onCreateNew, ruleEffects, ...passOnProps }: Props) => { const [open, setOpenStatus] = useState(true); - const { id, name, icon, description, dataElements, hideDueDate, repeatable } = stage; + const { id, name, icon, description, dataElements, hideDueDate, repeatable, enableUserAssignment } = stage; const hiddenProgramStage = hideProgramStage(ruleEffects, id); return ( @@ -57,6 +57,7 @@ export const StagePlain = ({ stage, events, classes, className, onCreateNew, rul dataElements={dataElements} hideDueDate={hideDueDate} repeatable={repeatable} + enableUserAssignment={enableUserAssignment} onCreateNew={onCreateNew} hiddenProgramStage={hiddenProgramStage} {...passOnProps} diff --git a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js index 86a4cad8bb..055befd20d 100644 --- a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js +++ b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/StageDetail.component.js @@ -66,6 +66,7 @@ const StageDetailPlain = (props: Props) => { dataElements, hideDueDate = false, repeatable = false, + enableUserAssignment = false, onEventClick, onViewAll, onCreateNew, @@ -76,7 +77,7 @@ const StageDetailPlain = (props: Props) => { sortDirection: SORT_DIRECTION.DESC, }; const { stage } = getProgramAndStageForProgram(programId, stageId); - const headerColumns = useComputeHeaderColumn(dataElements, hideDueDate, stage?.stageForm); + const headerColumns = useComputeHeaderColumn(dataElements, hideDueDate, enableUserAssignment, stage?.stageForm); const { loading, value: dataSource, error } = useComputeDataFromEvent(dataElements, events); diff --git a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useEventList.js b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useEventList.js index 25e9033688..ee914f4e0f 100644 --- a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useEventList.js +++ b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/hooks/useEventList.js @@ -20,10 +20,11 @@ import { SORT_DIRECTION, MULIT_TEXT_WITH_NO_OPTIONS_SET } from './constants'; import { isNotValidOptionSet } from '../../../../../../utils/isNotValidOptionSet'; import { useOrgUnitNames } from '../../../../../../metadataRetrieval/orgUnitName'; -const baseKeys = [{ id: 'status' }, { id: 'occurredAt' }, { id: 'orgUnitName' }, { id: 'scheduledAt' }, { id: 'comments' }]; +const baseKeys = [{ id: 'status' }, { id: 'occurredAt' }, { id: 'assignedUser' }, { id: 'orgUnitName' }, { id: 'scheduledAt' }, { id: 'comments' }]; const basedFieldTypes = [ { type: dataElementTypes.STATUS, resolveValue: convertStatusForView }, { type: dataElementTypes.DATE }, + { type: 'ASSIGNEE' }, { type: dataElementTypes.TEXT, resolveValue: convertOrgUnitForView }, { type: dataElementTypes.DATE }, { type: dataElementTypes.UNKNOWN, resolveValue: convertCommentForView }, @@ -31,6 +32,7 @@ const basedFieldTypes = [ const getBaseColumnHeaders = props => [ { header: i18n.t('Status'), sortDirection: SORT_DIRECTION.DEFAULT, isPredefined: true }, { header: props.formFoundation.getLabel('occurredAt'), sortDirection: SORT_DIRECTION.DEFAULT, isPredefined: true }, + { header: i18n.t('Assigned to'), sortDirection: SORT_DIRECTION.DEFAULT, isPredefined: true }, { header: i18n.t('Registering unit'), sortDirection: SORT_DIRECTION.DEFAULT, isPredefined: true }, { header: props.formFoundation.getLabel('scheduledAt'), sortDirection: SORT_DIRECTION.DEFAULT, isPredefined: true }, { header: '', sortDirection: null, isPredefined: true }, @@ -118,7 +120,7 @@ const useComputeDataFromEvent = (dataElements: Array, events: }; -const useComputeHeaderColumn = (dataElements: Array, hideDueDate: boolean, formFoundation: Object) => { +const useComputeHeaderColumn = (dataElements: Array, hideDueDate: boolean, enableUserAssignment: boolean, formFoundation: Object) => { const headerColumns = useMemo(() => { const dataElementHeaders = dataElements.reduce((acc, currDataElement) => { const { id, name, formName, type, optionSet } = currDataElement; @@ -132,9 +134,10 @@ const useComputeHeaderColumn = (dataElements: Array, hideDueDa return acc; }, []); return [ - ...getBaseColumns({ formFoundation }).filter(col => (hideDueDate ? col.id !== 'scheduledAt' : true)), + ...getBaseColumns({ formFoundation }) + .filter(col => (enableUserAssignment || col.id !== 'assignedUser') && (!hideDueDate || col.id !== 'scheduledAt')), ...dataElementHeaders]; - }, [dataElements, hideDueDate, formFoundation]); + }, [dataElements, hideDueDate, enableUserAssignment, formFoundation]); return headerColumns; }; diff --git a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/stageDetail.types.js b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/stageDetail.types.js index a5edeeab75..31d8c79dea 100644 --- a/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/stageDetail.types.js +++ b/src/core_modules/capture-core/components/WidgetStagesAndEvents/Stages/Stage/StageDetail/stageDetail.types.js @@ -7,6 +7,7 @@ import type { StageDataElement, StageCommonProps } from '../../../types/common.t eventName: string, hideDueDate?: boolean, repeatable?: boolean, + enableUserAssignment?: boolean, stageId: string, hiddenProgramStage?: boolean, ...CssClasses, diff --git a/src/core_modules/capture-core/components/WidgetStagesAndEvents/types/common.types.js b/src/core_modules/capture-core/components/WidgetStagesAndEvents/types/common.types.js index 1dc3709200..ef1a90c811 100644 --- a/src/core_modules/capture-core/components/WidgetStagesAndEvents/types/common.types.js +++ b/src/core_modules/capture-core/components/WidgetStagesAndEvents/types/common.types.js @@ -21,6 +21,7 @@ export type Stage = { description?: ?string, icon?: Icon, dataElements: Array, + enableUserAssignment: boolean, hideDueDate?: boolean, repeatable?: boolean } diff --git a/src/core_modules/capture-core/converters/serverToClient.js b/src/core_modules/capture-core/converters/serverToClient.js index 897a4cc13e..288948461e 100644 --- a/src/core_modules/capture-core/converters/serverToClient.js +++ b/src/core_modules/capture-core/converters/serverToClient.js @@ -11,6 +11,15 @@ function convertTime(d2Value: string) { return parseData.momentTime; } +const convertAssignedUserToClient = (assignedUser?: ApiAssignedUser) => + ((assignedUser && assignedUser.uid) ? { + id: assignedUser.uid, + name: assignedUser.displayName, + username: assignedUser.username, + firstName: assignedUser.firstName, + surname: assignedUser.surname, + } : null); + const optionSetConvertersForType = { [dataElementTypes.NUMBER]: parseNumber, [dataElementTypes.INTEGER]: parseNumber, @@ -51,6 +60,7 @@ const valueConvertersForType = { return { latitude: arr[1], longitude: arr[0] }; }, [dataElementTypes.POLYGON]: () => 'Polygon', + [dataElementTypes.ASSIGNEE]: convertAssignedUserToClient, }; export function convertValue(value: any, type: $Keys) { diff --git a/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js b/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js index 1e3f62f036..207918b8cb 100644 --- a/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js +++ b/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js @@ -1,5 +1,5 @@ // @flow -import { convertClientToServer } from '../../converters'; +import { convertClientToServer, convertAssigneeToServer } from '../../converters'; import { convertMainEvent } from './mainEventConverter'; import { dataElementTypes } from '../../metaData'; import { convertEventAttributeOptions } from '../convertEventAttributeOptions'; @@ -26,7 +26,7 @@ export function convertMainEventClientToServer(event: Object) { convertedValue = convertClientToServer(value, dataElementTypes.DATE); break; case 'assignee': - convertedValue = value && ({ uid: value.id }); + convertedValue = value && convertAssigneeToServer(value); break; default: convertedValue = value; diff --git a/src/core_modules/capture-core/utils/cachedDataHooks/useDataElementsFromIndexedDB.js b/src/core_modules/capture-core/utils/cachedDataHooks/useDataElementsFromIndexedDB.js new file mode 100644 index 0000000000..dbbf4f83c3 --- /dev/null +++ b/src/core_modules/capture-core/utils/cachedDataHooks/useDataElementsFromIndexedDB.js @@ -0,0 +1,32 @@ +// @flow +import type { UseQueryOptions } from 'react-query'; +import { userStores, getUserStorageController } from '../../storageControllers'; +import { useIndexedDBQuery } from '../reactQueryHelpers'; +import type { CachedDataElement } from '../../storageControllers/'; + +export const useDataElementsFromIndexedDB = (queryKey: Array, dataElementIds: ?Set, queryOptions?: UseQueryOptions<>): { + dataElements: ?Array, + isLoading: boolean, + isError: boolean, +} => { + const storageController = getUserStorageController(); + const { enabled = !!dataElementIds } = queryOptions ?? {}; + + const { data, isLoading, isError } = useIndexedDBQuery( + ['dataElements', ...queryKey], + () => storageController.getAll( + userStores.DATA_ELEMENTS, { + // $FlowIgnore - the enabled prop guarantees that dataElementIds will be defined + predicate: dataElement => dataElementIds.has(dataElement.id), + }, + ), { + enabled, + }, + ); + + return { + dataElements: data, + isLoading, + isError, + }; +}; diff --git a/src/core_modules/capture-core/utils/cachedDataHooks/useOptionSetsFromIndexedDB.js b/src/core_modules/capture-core/utils/cachedDataHooks/useOptionSetsFromIndexedDB.js new file mode 100644 index 0000000000..f0480779ee --- /dev/null +++ b/src/core_modules/capture-core/utils/cachedDataHooks/useOptionSetsFromIndexedDB.js @@ -0,0 +1,32 @@ +// @flow +import type { UseQueryOptions } from 'react-query'; +import { userStores, getUserStorageController } from '../../storageControllers'; +import { useIndexedDBQuery } from '../reactQueryHelpers'; +import type { CachedOptionSet } from '../../storageControllers/'; + +export const useOptionSetsFromIndexedDB = (queryKey: Array, optionSetIds: ?Set, queryOptions?: UseQueryOptions<>): { + optionSets: ?Array, + isLoading: boolean, + isError: boolean, +} => { + const storageController = getUserStorageController(); + const { enabled = !!optionSetIds } = queryOptions ?? {}; + + const { data, isLoading, isError } = useIndexedDBQuery( + ['optionSets', ...queryKey], + () => storageController.getAll( + userStores.OPTION_SETS, { + // $FlowIgnore - the enabled prop guarantees that optionSetIds will be defined + predicate: optionSet => optionSetIds.has(optionSet.id), + }, + ), { + enabled, + }, + ); + + return { + optionSets: data, + isLoading, + isError, + }; +}; diff --git a/src/core_modules/capture-core/utils/cachedDataHooks/useProgramFromIndexedDB.js b/src/core_modules/capture-core/utils/cachedDataHooks/useProgramFromIndexedDB.js index c8a73f7838..d5a1c8a02e 100644 --- a/src/core_modules/capture-core/utils/cachedDataHooks/useProgramFromIndexedDB.js +++ b/src/core_modules/capture-core/utils/cachedDataHooks/useProgramFromIndexedDB.js @@ -4,9 +4,9 @@ import { userStores, getUserStorageController } from '../../storageControllers'; import { useIndexedDBQuery } from '../reactQueryHelpers'; -export const useProgramFromIndexedDB = (programId: ?string, QueryOptions?: UseQueryOptions<>) => { +export const useProgramFromIndexedDB = (programId: ?string, queryOptions?: UseQueryOptions<>) => { const storageController = getUserStorageController(); - const { enabled = true } = QueryOptions ?? {}; + const { enabled = true } = queryOptions ?? {}; const { data, isLoading, isError } = useIndexedDBQuery( // $FlowFixMe - only gets called when programId is defined because of enabled diff --git a/src/core_modules/capture-core/utils/reactQueryHelpers/query/useMetadataQuery.js b/src/core_modules/capture-core/utils/reactQueryHelpers/query/useMetadataQuery.js index ee31061b8c..2452405547 100644 --- a/src/core_modules/capture-core/utils/reactQueryHelpers/query/useMetadataQuery.js +++ b/src/core_modules/capture-core/utils/reactQueryHelpers/query/useMetadataQuery.js @@ -5,7 +5,7 @@ import { useDataEngine, type ResourceQuery } from '@dhis2/app-runtime'; import type { QueryFunction, UseQueryOptions } from 'react-query'; import { IndexedDBError } from '../../../../capture-core-utils/storage/IndexedDBError/IndexedDBError'; import type { Result } from './useMetadataQuery.types'; -import { ReactQueryAppNamespace } from '../reactQueryHelpers.const'; +import { ReactQueryAppNamespace, IndexedDBNamespace } from '../reactQueryHelpers.const'; const throwErrorForIndexedDB = (error) => { if (error instanceof IndexedDBError) { @@ -43,7 +43,7 @@ export const useIndexedDBQuery = ( queryFn: QueryFunction, queryOptions?: UseQueryOptions, ): Result => - useAsyncMetadata(queryKey, queryFn, { + useAsyncMetadata([IndexedDBNamespace, ...queryKey], queryFn, { cacheTime: 0, ...queryOptions, onError: (error) => { diff --git a/src/core_modules/capture-core/utils/reactQueryHelpers/reactQueryHelpers.const.js b/src/core_modules/capture-core/utils/reactQueryHelpers/reactQueryHelpers.const.js index 2659b304ba..5256c91b69 100644 --- a/src/core_modules/capture-core/utils/reactQueryHelpers/reactQueryHelpers.const.js +++ b/src/core_modules/capture-core/utils/reactQueryHelpers/reactQueryHelpers.const.js @@ -1,4 +1,4 @@ - // @flow export const ReactQueryAppNamespace = 'capture'; +export const IndexedDBNamespace = 'indexedDB'; From d5d4ded2ecfa407707e4be8fc4e487a22c76f590 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Mon, 18 Dec 2023 14:31:08 +0000 Subject: [PATCH 26/32] chore(release): cut 100.50.0 [skip release] # [100.50.0](https://github.com/dhis2/capture-app/compare/v100.49.0...v100.50.0) (2023-12-18) ### Features * [DHIS-11419] display assigned users on events in enrollment overview page ([#3453](https://github.com/dhis2/capture-app/issues/3453)) ([44fb2be](https://github.com/dhis2/capture-app/commit/44fb2bedf0e2f9d394c58d5a588087cff2c8fa3c)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9f2945b4b..4adb282186 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [100.50.0](https://github.com/dhis2/capture-app/compare/v100.49.0...v100.50.0) (2023-12-18) + + +### Features + +* [DHIS-11419] display assigned users on events in enrollment overview page ([#3453](https://github.com/dhis2/capture-app/issues/3453)) ([44fb2be](https://github.com/dhis2/capture-app/commit/44fb2bedf0e2f9d394c58d5a588087cff2c8fa3c)) + # [100.49.0](https://github.com/dhis2/capture-app/compare/v100.48.0...v100.49.0) (2023-12-18) diff --git a/package.json b/package.json index 8220158c9b..dc256cc47b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.49.0", + "version": "100.50.0", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.49.0", + "@dhis2/rules-engine-javascript": "100.50.0", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index d883e1427b..a305d3c6c9 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.49.0", + "version": "100.50.0", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From ef304499fda3296320ca71fae72d33f2dfad88fa Mon Sep 17 00:00:00 2001 From: eirikhaugstulen Date: Wed, 20 Dec 2023 12:56:13 +0100 Subject: [PATCH 27/32] fix: [DHIS2-16317] Incorrect error message on orgUnit type data element (#3484) Co-authored-by: Tony Valle --- .../OrgUnitField/SingleOrgUnitSelectField.component.js | 6 +++--- .../TrackedEntityRelationshipsWrapper.component.js | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js b/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js index 7946993a79..6c252f087b 100644 --- a/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js +++ b/src/core_modules/capture-core/components/FormFields/New/Fields/OrgUnitField/SingleOrgUnitSelectField.component.js @@ -13,7 +13,7 @@ const getStyles = () => ({ type OrgUnitValue = { id: string, - displayName: string, + name: string, path: string, } @@ -44,7 +44,7 @@ class SingleOrgUnitSelectFieldPlain extends React.Component { const { classes } = this.props; return (
- {selectedOrgUnit.displayName} + {selectedOrgUnit.name}
); } @@ -52,7 +52,7 @@ class SingleOrgUnitSelectFieldPlain extends React.Component { onSelectOrgUnit = (orgUnit: Object) => { this.props.onBlur({ id: orgUnit.id, - displayName: orgUnit.displayName, + name: orgUnit.displayName, path: orgUnit.path, }); } diff --git a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js index 7be6a4a07b..28b3f0b25d 100644 --- a/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js +++ b/src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TrackedEntityRelationshipsWrapper/TrackedEntityRelationshipsWrapper.component.js @@ -15,7 +15,7 @@ import { } from '../../../NewRelationship/TeiRelationship/SearchResults/TeiRelationshipSearchResults.component'; import { ResultsPageSizeContext } from '../../../shared-contexts'; import { RegisterTei } from '../RegisterTei'; -import { useOrganisationUnit } from '../../../../../dataQueries'; +import { useCoreOrgUnit } from '../../../../../metadataRetrieval/coreOrgUnit'; export const TrackedEntityRelationshipsWrapper = ({ trackedEntityTypeId, @@ -29,7 +29,8 @@ export const TrackedEntityRelationshipsWrapper = ({ }: Props) => { const dispatch = useDispatch(); const { relationshipTypes, isError } = useTEIRelationshipsWidgetMetadata(); - const { orgUnit: initialOrgUnit } = useOrganisationUnit(orgUnitId, 'id,displayName,code'); + const { orgUnit } = useCoreOrgUnit(orgUnitId); + const initialOrgUnit = orgUnit ? { id: orgUnitId, name: orgUnit.name, path: orgUnit.path } : null; const onSelectFindMode = ({ findMode, relationshipConstraint }: OnSelectFindModeProps) => { dispatch(selectFindMode({ From 1fe250694e4f039464d79fee34b8ed400d5232b5 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Wed, 20 Dec 2023 12:10:42 +0000 Subject: [PATCH 28/32] chore(release): cut 100.50.1 [skip release] ## [100.50.1](https://github.com/dhis2/capture-app/compare/v100.50.0...v100.50.1) (2023-12-20) ### Bug Fixes * [DHIS2-16317] Incorrect error message on orgUnit type data element ([#3484](https://github.com/dhis2/capture-app/issues/3484)) ([ef30449](https://github.com/dhis2/capture-app/commit/ef304499fda3296320ca71fae72d33f2dfad88fa)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4adb282186..dbfc5f209a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [100.50.1](https://github.com/dhis2/capture-app/compare/v100.50.0...v100.50.1) (2023-12-20) + + +### Bug Fixes + +* [DHIS2-16317] Incorrect error message on orgUnit type data element ([#3484](https://github.com/dhis2/capture-app/issues/3484)) ([ef30449](https://github.com/dhis2/capture-app/commit/ef304499fda3296320ca71fae72d33f2dfad88fa)) + # [100.50.0](https://github.com/dhis2/capture-app/compare/v100.49.0...v100.50.0) (2023-12-18) diff --git a/package.json b/package.json index dc256cc47b..d9a77ae34c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.50.0", + "version": "100.50.1", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.50.0", + "@dhis2/rules-engine-javascript": "100.50.1", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index a305d3c6c9..e70793a3b3 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.50.0", + "version": "100.50.1", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From b5e038b823128386f7106da46025a2a38a00db1b Mon Sep 17 00:00:00 2001 From: Tony Valle <79843014+superskip@users.noreply.github.com> Date: Wed, 20 Dec 2023 14:22:18 +0100 Subject: [PATCH 29/32] fix: [TECH-1676] cypress test deleting wrong working list template (#3489) --- .../WorkingLists/TeiWorkingLists/TeiWorkingListsUser/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser/index.js b/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser/index.js index c6adb4c683..aaf5c97c93 100644 --- a/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser/index.js +++ b/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsUser/index.js @@ -567,6 +567,7 @@ When('you create a copy of the working list', }); cy.wait('@newTrackerFilter', { timeout: 30000 }); + cy.url({ timeout: 30000 }).should('not.include', 'selectedTemplateId=PpGINOT00UX'); cy.reload(); }); From 27547a87583ce0d36880c6d98bf416dd5f4a80d9 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Wed, 20 Dec 2023 13:33:22 +0000 Subject: [PATCH 30/32] chore(release): cut 100.50.2 [skip release] ## [100.50.2](https://github.com/dhis2/capture-app/compare/v100.50.1...v100.50.2) (2023-12-20) ### Bug Fixes * [TECH-1676] cypress test deleting wrong working list template ([#3489](https://github.com/dhis2/capture-app/issues/3489)) ([b5e038b](https://github.com/dhis2/capture-app/commit/b5e038b823128386f7106da46025a2a38a00db1b)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbfc5f209a..01bba7d5e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [100.50.2](https://github.com/dhis2/capture-app/compare/v100.50.1...v100.50.2) (2023-12-20) + + +### Bug Fixes + +* [TECH-1676] cypress test deleting wrong working list template ([#3489](https://github.com/dhis2/capture-app/issues/3489)) ([b5e038b](https://github.com/dhis2/capture-app/commit/b5e038b823128386f7106da46025a2a38a00db1b)) + ## [100.50.1](https://github.com/dhis2/capture-app/compare/v100.50.0...v100.50.1) (2023-12-20) diff --git a/package.json b/package.json index d9a77ae34c..7370f0a32c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.50.1", + "version": "100.50.2", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.50.1", + "@dhis2/rules-engine-javascript": "100.50.2", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index e70793a3b3..97370b58a1 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.50.1", + "version": "100.50.2", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From c92b38e8f775d20476fc0e2619f95ba48377ec5a Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Sun, 24 Dec 2023 02:36:58 +0100 Subject: [PATCH 31/32] fix(translations): sync translations from transifex (master) Automatically merged. --- i18n/lo.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/i18n/lo.po b/i18n/lo.po index 21bbeecd37..4016b96aca 100644 --- a/i18n/lo.po +++ b/i18n/lo.po @@ -1,16 +1,16 @@ # # Translators: -# Saysamone Sibounma, 2023 # Philip Larsen Donnelly, 2023 # Viktor Varland , 2023 # Thuy Nguyen , 2023 +# Saysamone Sibounma, 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" "POT-Creation-Date: 2023-09-12T06:24:49.265Z\n" "PO-Revision-Date: 2019-06-27 07:31+0000\n" -"Last-Translator: Thuy Nguyen , 2023\n" +"Last-Translator: Saysamone Sibounma, 2023\n" "Language-Team: Lao (https://app.transifex.com/hisp-uio/teams/100509/lo/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -587,7 +587,7 @@ msgid "Offline" msgstr "ບໍ່ມີການເຊື່ອມຕໍ່" msgid "Syncing" -msgstr "" +msgstr "ກຳລັງອັບເດດຂໍ້ມູນໃຫ້ຄືກັນ" msgid "Add comment" msgstr "" @@ -1248,7 +1248,7 @@ msgid "Scheduled date cannot be changed for {{ eventStatus }} events" msgstr "" msgid "Event completed" -msgstr "" +msgstr "ກິດຈະກຳສຳເລັດແລ້ວ" msgid "Back to all stages and events" msgstr "" From 433afa5553555bb2e045e8ae5d7af53edae94ff5 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Sun, 24 Dec 2023 01:46:16 +0000 Subject: [PATCH 32/32] chore(release): cut 100.50.3 [skip release] ## [100.50.3](https://github.com/dhis2/capture-app/compare/v100.50.2...v100.50.3) (2023-12-24) ### Bug Fixes * **translations:** sync translations from transifex (master) ([c92b38e](https://github.com/dhis2/capture-app/commit/c92b38e8f775d20476fc0e2619f95ba48377ec5a)) --- CHANGELOG.md | 7 +++++++ package.json | 4 ++-- packages/rules-engine/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01bba7d5e8..a8bdf704ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [100.50.3](https://github.com/dhis2/capture-app/compare/v100.50.2...v100.50.3) (2023-12-24) + + +### Bug Fixes + +* **translations:** sync translations from transifex (master) ([c92b38e](https://github.com/dhis2/capture-app/commit/c92b38e8f775d20476fc0e2619f95ba48377ec5a)) + ## [100.50.2](https://github.com/dhis2/capture-app/compare/v100.50.1...v100.50.2) (2023-12-20) diff --git a/package.json b/package.json index 7370f0a32c..b407d2b323 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.50.2", + "version": "100.50.3", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.50.2", + "@dhis2/rules-engine-javascript": "100.50.3", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", diff --git a/packages/rules-engine/package.json b/packages/rules-engine/package.json index 97370b58a1..56222b22a5 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.50.2", + "version": "100.50.3", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": {