From 005877ce88a2d28dfc053b39869090cd9573bfdd Mon Sep 17 00:00:00 2001 From: Simona Domnisoru Date: Mon, 22 Apr 2024 16:21:34 +0200 Subject: [PATCH 01/19] fix: [DHIS2-14938] trigger error on complete (#3594) --- .../EditEventDataEntry.component.js | 2 +- .../EditEventDataEntry/editEventDataEntry.epics.js | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.component.js b/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.component.js index 94bd13407c..ac2df74641 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.component.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.component.js @@ -357,7 +357,7 @@ const AOCSettings = { }; const saveHandlerConfig = { - onIsCompleting: (props: Object) => props.completeDataEntryFieldValue, + onIsCompleting: (props: Object) => props.completeDataEntryFieldValue === 'true', onFilterProps: (props: Object) => { const { completeDataEntryFieldValue, ...passOnProps } = props; return passOnProps; diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/editEventDataEntry.epics.js b/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/editEventDataEntry.epics.js index 72f595a621..1ab650c1a4 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/editEventDataEntry.epics.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/editEventDataEntry.epics.js @@ -163,15 +163,21 @@ export const saveEditedEventEpic = (action$: InputObservable, store: ReduxStore) export const saveEditedEventSucceededEpic = (action$: InputObservable) => action$.pipe( ofType(actionTypes.EDIT_EVENT_DATA_ENTRY_SAVED), + filter((action) => { + const { + meta: { triggerAction }, + } = action; + return ( + triggerAction === enrollmentSiteActionTypes.COMMIT_ENROLLMENT_EVENT || + triggerAction === enrollmentEditEventActionTypes.EVENT_SAVE_ENROLLMENT_COMPLETE_SUCCESS + ); + }), map((action) => { const meta = action.meta; - if (meta.triggerAction === enrollmentSiteActionTypes.COMMIT_ENROLLMENT_EVENT) { - return commitEnrollmentEvent(meta.eventId); - } if (meta.triggerAction === enrollmentEditEventActionTypes.EVENT_SAVE_ENROLLMENT_COMPLETE_SUCCESS) { return commitEnrollmentAndEvents(); } - return EMPTY; + return commitEnrollmentEvent(meta.eventId); })); export const saveEditedEventFailedEpic = (action$: InputObservable, store: ReduxStore) => From f2007e368b0844730ed36c654e1e01323fb92ed2 Mon Sep 17 00:00:00 2001 From: Simona Domnisoru Date: Mon, 22 Apr 2024 16:22:20 +0200 Subject: [PATCH 02/19] fix: [DHIS2-16999] filter assign rule effects in the view event page (#3597) --- .../ViewEventDataEntry/viewEventDataEntry.actions.js | 6 ++++-- .../capture-core/rules/filterApplicableRuleEffects.js | 6 ++++++ src/core_modules/capture-core/rules/index.js | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 src/core_modules/capture-core/rules/filterApplicableRuleEffects.js diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/ViewEventDataEntry/viewEventDataEntry.actions.js b/src/core_modules/capture-core/components/WidgetEventEdit/ViewEventDataEntry/viewEventDataEntry.actions.js index cf1aeba1b3..281525eebc 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/ViewEventDataEntry/viewEventDataEntry.actions.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/ViewEventDataEntry/viewEventDataEntry.actions.js @@ -1,6 +1,6 @@ // @flow import i18n from '@dhis2/d2-i18n'; -import { type OrgUnit } from '@dhis2/rules-engine-javascript'; +import { type OrgUnit, effectActions } from '@dhis2/rules-engine-javascript'; import { actionCreator } from '../../../actions/actions.utils'; import type { RenderFoundation, Program } from '../../../metaData'; import { getConvertGeometryIn, convertGeometryOut, convertStatusOut } from '../../DataEntries'; @@ -10,6 +10,7 @@ import { getApplicableRuleEffectsForTrackerProgram, getApplicableRuleEffectsForEventProgram, updateRulesEffects, + filterApplicableRuleEffects, } from '../../../rules'; import { dataElementTypes } from '../../../metaData'; import { convertClientToForm } from '../../../converters'; @@ -145,10 +146,11 @@ export const loadViewEventDataEntry = currentEvent, }); } + const filteredEffects = filterApplicableRuleEffects(effects, effectActions.ASSIGN_VALUE); return [ ...dataEntryActions, - updateRulesEffects(effects, formId), + updateRulesEffects(filteredEffects, formId), actionCreator(actionTypes.VIEW_EVENT_DATA_ENTRY_LOADED)({ loadedValues: { dataEntryValues, formValues, eventContainer, orgUnit }, // $FlowFixMe[prop-missing] automated comment diff --git a/src/core_modules/capture-core/rules/filterApplicableRuleEffects.js b/src/core_modules/capture-core/rules/filterApplicableRuleEffects.js new file mode 100644 index 0000000000..f47b0b1ec9 --- /dev/null +++ b/src/core_modules/capture-core/rules/filterApplicableRuleEffects.js @@ -0,0 +1,6 @@ +// @flow + +export const filterApplicableRuleEffects = (rulesEffects: Object = {}, effectAction: string) => { + const { [effectAction]: _, ...filteredEffects } = rulesEffects; + return filteredEffects; +}; diff --git a/src/core_modules/capture-core/rules/index.js b/src/core_modules/capture-core/rules/index.js index 2dfc96f6c7..7eedf9ff6d 100644 --- a/src/core_modules/capture-core/rules/index.js +++ b/src/core_modules/capture-core/rules/index.js @@ -9,3 +9,4 @@ export { updateRulesEffects, rulesEffectsActionTypes } from './rulesEngine.actio export type { FieldData } from './inputHelpers'; export { postProcessRulesEffects } from './postProcessRulesEffects'; export { buildEffectsHierarchy } from './buildEffectsHierarchy'; +export { filterApplicableRuleEffects } from './filterApplicableRuleEffects'; From eb9152a0fddba635853c944a187c3b03da83be25 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Mon, 22 Apr 2024 14:37:44 +0000 Subject: [PATCH 03/19] chore(release): cut 100.67.12 [skip release] ## [100.67.12](https://github.com/dhis2/capture-app/compare/v100.67.11...v100.67.12) (2024-04-22) ### Bug Fixes * [DHIS2-14938] trigger error on complete ([#3594](https://github.com/dhis2/capture-app/issues/3594)) ([005877c](https://github.com/dhis2/capture-app/commit/005877ce88a2d28dfc053b39869090cd9573bfdd)) * [DHIS2-16999] filter assign rule effects in the view event page ([#3597](https://github.com/dhis2/capture-app/issues/3597)) ([f2007e3](https://github.com/dhis2/capture-app/commit/f2007e368b0844730ed36c654e1e01323fb92ed2)) --- 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 90cb62dded..4e24c98c0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## [100.67.12](https://github.com/dhis2/capture-app/compare/v100.67.11...v100.67.12) (2024-04-22) + + +### Bug Fixes + +* [DHIS2-14938] trigger error on complete ([#3594](https://github.com/dhis2/capture-app/issues/3594)) ([005877c](https://github.com/dhis2/capture-app/commit/005877ce88a2d28dfc053b39869090cd9573bfdd)) +* [DHIS2-16999] filter assign rule effects in the view event page ([#3597](https://github.com/dhis2/capture-app/issues/3597)) ([f2007e3](https://github.com/dhis2/capture-app/commit/f2007e368b0844730ed36c654e1e01323fb92ed2)) + ## [100.67.11](https://github.com/dhis2/capture-app/compare/v100.67.10...v100.67.11) (2024-04-14) diff --git a/package.json b/package.json index db16b93213..05ab5030bd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "capture-app", "homepage": ".", - "version": "100.67.11", + "version": "100.67.12", "cacheVersion": "7", "serverVersion": "38", "license": "BSD-3-Clause", @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "100.67.11", + "@dhis2/rules-engine-javascript": "100.67.12", "@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 7484fc82eb..7e5afcc77a 100644 --- a/packages/rules-engine/package.json +++ b/packages/rules-engine/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/rules-engine-javascript", - "version": "100.67.11", + "version": "100.67.12", "license": "BSD-3-Clause", "main": "./build/cjs/index.js", "scripts": { From 85f38bedd60c307788cf17237338765bf9fed7f0 Mon Sep 17 00:00:00 2001 From: eirikhaugstulen Date: Thu, 25 Apr 2024 10:24:08 +0200 Subject: [PATCH 04/19] feat: [DHIS2-13299][DHIS2-16291] Related Stages (#3488) --- i18n/en.pot | 31 +++ .../storage/IndexedDBAdapter.js | 10 +- .../storage/StorageController.js | 4 +- .../validators/form/orgUnit.validator.js | 2 +- .../withAskToCompleteEnrollment.js | 8 +- .../DataEntry/CancelButton.component.js | 2 + .../DataEntry/DataEntry.component.js | 1 - .../components/DataEntry/withCancelButton.js | 4 +- .../DataSection/DataSection.component.js | 5 +- .../EnrollmentAddEventPage.epics.js | 116 +++++++--- ...EnrollmentAddEventPageDefault.container.js | 44 ++-- .../EnrollmentAddEventPageDefault.types.js | 1 - .../NewEventWorkspace.component.js | 2 - .../newEventWorkspace.types.js | 1 - .../Pages/EnrollmentAddEvent/index.js | 2 - .../LayoutComponentConfig.js | 2 - .../enrollment.actions.js | 29 ++- .../common/EnrollmentOverviewDomain/index.js | 3 +- .../Relationships/relationships.types.js | 1 + .../WidgetEnrollment/enrollment.types.js | 7 + .../accessVerification.types.js | 1 - .../DataEntry/dataEntryFieldLabels.module.css | 2 +- .../FinishButtons/FinishButtons.component.js | 18 +- .../FinishButtons/finishButtons.types.js | 3 + .../Validated/Validated.component.js | 14 ++ .../Validated/Validated.container.js | 215 ++++++++++-------- .../Validated/getConvertedAddEvent.js | 43 ++-- .../getConvertedRelatedStageEvent.js | 120 ++++++++++ .../getConvertedRelatedStageEvent.types.js | 29 +++ .../getConvertedRelatedStageEvent/index.js | 2 + .../Validated/index.js | 2 +- .../Validated/useBuildNewEventPayload.js | 168 ++++++++++++++ .../Validated/validated.actions.js | 159 ++++--------- .../Validated/validated.epics.js | 122 ++-------- .../Validated/validated.types.js | 35 +++ .../WidgetEnrollmentEventNew.container.js | 2 - .../WidgetEnrollmentEventNew.types.js | 1 - .../WidgetEnrollmentEventNew/common.types.js | 1 - .../WidgetEnrollmentEventNew/index.js | 2 +- .../WidgetEventSchedule.epics.js | 3 +- .../DateFieldForRelatedStages.js | 66 ++++++ .../OrgUnitSelectorForRelatedStages.js | 77 +++++++ .../FormComponents/commonProps.js | 6 + .../dataEntryFieldLabels.module.css | 3 + .../FormComponents/index.js | 4 + .../LinkToExisting.component.js | 74 ++++++ .../LinkToExisting/LinkToExisting.types.js | 14 ++ .../LinkToExisting/index.js | 2 + .../RelatedStagesActions.component.js | 149 ++++++++++++ .../RelatedStagesActions.types.js | 38 ++++ .../RelatedStagesActions/index.js | 3 + .../ScheduleInOrgUnit.container.js | 107 +++++++++ .../ScheduleInOrgUnit/index.js | 2 + .../WidgetRelatedStages.component.js | 110 +++++++++ .../WidgetRelatedStages.constants.js | 11 + .../WidgetRelatedStages.types.js | 33 +++ .../WidgetRelatedStages/constants.js | 19 ++ .../hooks/useAvailableRelatedStageEvents.js | 83 +++++++ .../hooks/useStageLabels.js | 34 +++ .../components/WidgetRelatedStages/index.js | 4 + .../ValidationFunctions.js | 70 ++++++ .../relatedStageEventIsValid.js | 32 +++ .../relatedStageEventIsValid.types.js | 15 ++ .../WidgetRelatedStages/useRelatedStages.js | 90 ++++++++ .../RelationshipType/RelationshipType.js | 9 + .../storeRelationshipTypes.js | 2 +- .../enrollmentDomain.reducerDescription.js | 141 ++++++++---- .../query/useApiDataQuery.js | 2 +- src/epics/trackerCapture.epics.js | 6 - 69 files changed, 1952 insertions(+), 471 deletions(-) create mode 100644 src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/getConvertedRelatedStageEvent/getConvertedRelatedStageEvent.js create mode 100644 src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/getConvertedRelatedStageEvent/getConvertedRelatedStageEvent.types.js create mode 100644 src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/getConvertedRelatedStageEvent/index.js create mode 100644 src/core_modules/capture-core/components/WidgetEnrollmentEventNew/Validated/useBuildNewEventPayload.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/FormComponents/DateFieldForRelatedStages.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/FormComponents/OrgUnitSelectorForRelatedStages.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/FormComponents/commonProps.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/FormComponents/dataEntryFieldLabels.module.css create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/FormComponents/index.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/LinkToExisting/LinkToExisting.component.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/LinkToExisting/LinkToExisting.types.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/LinkToExisting/index.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/RelatedStagesActions/RelatedStagesActions.component.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/RelatedStagesActions/RelatedStagesActions.types.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/RelatedStagesActions/index.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/ScheduleInOrgUnit/ScheduleInOrgUnit.container.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/ScheduleInOrgUnit/index.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/WidgetRelatedStages.component.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/WidgetRelatedStages.constants.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/WidgetRelatedStages.types.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/constants.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/hooks/useAvailableRelatedStageEvents.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/hooks/useStageLabels.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/index.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/relatedStageEventIsValid/ValidationFunctions.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/relatedStageEventIsValid/relatedStageEventIsValid.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/relatedStageEventIsValid/relatedStageEventIsValid.types.js create mode 100644 src/core_modules/capture-core/components/WidgetRelatedStages/useRelatedStages.js diff --git a/i18n/en.pot b/i18n/en.pot index 6c9c678fbc..723eb3a41d 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -1448,6 +1448,37 @@ msgstr "{{trackedEntityTypeName}} profile" msgid "tracked entity instance" msgstr "tracked entity instance" +msgid "Link to an existing {{linkableStageLabel}}" +msgstr "Link to an existing {{linkableStageLabel}}" + +msgid "Choose a {{linkableStageLabel}}" +msgstr "Choose a {{linkableStageLabel}}" + +msgid "Ambiguous relationships, contact system administrator" +msgstr "Ambiguous relationships, contact system administrator" + +msgid "" +"Enter {{linkableStageLabel}} details in the next step after completing this " +"{{currentStageLabel}}." +msgstr "" +"Enter {{linkableStageLabel}} details in the next step after completing this " +"{{currentStageLabel}}." + +msgid "Enter details now" +msgstr "Enter details now" + +msgid "Link to an existing" +msgstr "Link to an existing" + +msgid "Scheduled date" +msgstr "Scheduled date" + +msgid "Report date" +msgstr "Report date" + +msgid "Please select a valid event" +msgstr "Please select a valid event" + msgid "New {{ eventName }} event" msgstr "New {{ eventName }} event" diff --git a/src/core_modules/capture-core-utils/storage/IndexedDBAdapter.js b/src/core_modules/capture-core-utils/storage/IndexedDBAdapter.js index 40b4400d99..df48a1512a 100644 --- a/src/core_modules/capture-core-utils/storage/IndexedDBAdapter.js +++ b/src/core_modules/capture-core-utils/storage/IndexedDBAdapter.js @@ -78,7 +78,7 @@ export class IndexedDBAdapter { }); } - static get(store, key, db, keyPath) { + static get(store, key, options, db, keyPath) { return new Promise((resolve, reject) => { let tx; let catchError; @@ -105,11 +105,13 @@ export class IndexedDBAdapter { const request = objectStore.get(key); request.onsuccess = (e) => { const object = e.target.result; + const { project } = options || {}; if (isDefined(object)) { object[keyPath] = key; } - resultObject = object; + + resultObject = project ? project(object) : object; }; } catch (error) { if (tx) { @@ -392,8 +394,8 @@ export class IndexedDBAdapter { }); } - get(store, key) { - return IndexedDBAdapter.get(store, key, this.db, this.keyPath); + get(store, key, options) { + return IndexedDBAdapter.get(store, key, options, this.db, this.keyPath); } // eslint-disable-next-line class-methods-use-this diff --git a/src/core_modules/capture-core-utils/storage/StorageController.js b/src/core_modules/capture-core-utils/storage/StorageController.js index 3bd315ec03..be7fdd3ae1 100644 --- a/src/core_modules/capture-core-utils/storage/StorageController.js +++ b/src/core_modules/capture-core-utils/storage/StorageController.js @@ -188,7 +188,7 @@ export class StorageController { } // using async ensures that the the return value is wrapped in a promise - async get(store, key) { + async get(store, key, options) { this.throwIfNotOpen(); this.throwIfStoreNotFound(store, 'get'); @@ -200,7 +200,7 @@ export class StorageController { ); } - return this.adapter.get(store, key); + return this.adapter.get(store, key, options); } // using async ensures that the the return value is wrapped in a promise diff --git a/src/core_modules/capture-core-utils/validators/form/orgUnit.validator.js b/src/core_modules/capture-core-utils/validators/form/orgUnit.validator.js index 43b9a8d83e..abd7ce48ba 100644 --- a/src/core_modules/capture-core-utils/validators/form/orgUnit.validator.js +++ b/src/core_modules/capture-core-utils/validators/form/orgUnit.validator.js @@ -13,7 +13,7 @@ type OrgUnitValue = { path: string, } -export const isValidOrgUnit = (value: OrgUnitValue) => { +export const isValidOrgUnit = (value: ?OrgUnitValue) => { const valid = !!(value && value.id && value.name); return valid; }; diff --git a/src/core_modules/capture-core/components/DataEntries/common/trackerEvent/withAskToCompleteEnrollment/withAskToCompleteEnrollment.js b/src/core_modules/capture-core/components/DataEntries/common/trackerEvent/withAskToCompleteEnrollment/withAskToCompleteEnrollment.js index 84e955b839..b1d2cee393 100644 --- a/src/core_modules/capture-core/components/DataEntries/common/trackerEvent/withAskToCompleteEnrollment/withAskToCompleteEnrollment.js +++ b/src/core_modules/capture-core/components/DataEntries/common/trackerEvent/withAskToCompleteEnrollment/withAskToCompleteEnrollment.js @@ -6,6 +6,8 @@ import { CompleteModal } from './CompleteModal'; import { statusTypes as eventStatuses } from '../../../../../events/statusTypes'; import { type RenderFoundation } from '../../../../../metaData'; import { addEventSaveTypes } from '../../../../WidgetEnrollmentEventNew/DataEntry/addEventSaveTypes'; +import { actions as LinkModes } from '../../../../WidgetRelatedStages/constants'; +import type { RelatedStageRefPayload } from '../../../../WidgetEnrollmentEventNew/Validated/validated.types'; type Props = { onSave: (eventId: string, dataEntryId: string, formFoundation: RenderFoundation, saveType?: ?string) => void, @@ -13,6 +15,7 @@ type Props = { isCompleted?: boolean, eventId?: ?string, formFoundation: RenderFoundation, + relatedStageRef: { current?: ?RelatedStageRefPayload }, onSaveAndCompleteEnrollment: ( eventId: string, dataEntryId: string, @@ -28,6 +31,7 @@ const getAskToCompleteEnrollment = (InnerComponent: ComponentType) => (prop isCompleted, onSaveAndCompleteEnrollment, eventId, + relatedStageRef, ...passOnProps } = props; const enrollment = useSelector(({ enrollmentDomain }) => enrollmentDomain?.enrollment); @@ -54,8 +58,9 @@ const getAskToCompleteEnrollment = (InnerComponent: ComponentType) => (prop formFoundation: RenderFoundation, saveType?: string, ) => { + const { linkMode } = relatedStageRef?.current?.getLinkedStageValues() ?? {}; eventDataToSave.current = { itemId, dataEntryId, formFoundation, saveType }; - if (askCompleteEnrollmentOnEventComplete && (isCompleted || saveType === addEventSaveTypes.COMPLETE)) { + if (askCompleteEnrollmentOnEventComplete && (isCompleted || saveType === addEventSaveTypes.COMPLETE) && linkMode !== LinkModes.ENTER_DATA) { setOpenCompleteModal(true); } else { onSave(itemId, dataEntryId, formFoundation, saveType); @@ -66,6 +71,7 @@ const getAskToCompleteEnrollment = (InnerComponent: ComponentType) => (prop <> void, } @@ -36,6 +37,7 @@ export class CancelButtonComponent extends React.Component {