From d937f35ecf8f4cc7b278b13f108eb2fdba075985 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Sun, 26 Jan 2025 12:01:25 +0100 Subject: [PATCH 01/15] feat: add org unit field to form --- .../EditEventDataEntry.component.js | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) 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 7c2103b71e..d3505913bd 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 @@ -33,6 +33,7 @@ import { withDefaultFieldContainer, withDefaultShouldUpdateInterface, VirtualizedSelectField, + SingleOrgUnitSelectField, } from '../../FormFields/New'; import { statusTypes, translatedStatusTypes } from '../../../events/statusTypes'; import labelTypeClasses from '../DataEntry/dataEntryFieldLabels.module.css'; @@ -48,6 +49,7 @@ import { withDataEntryFields, } from '../../DataEntryDhis2Helpers/'; import type { UserFormField } from '../../FormFields/UserField'; +import { getOrgUnitValidatorContainers } from '../DataEntry/fieldValidators'; const tabMode = Object.freeze({ REPORT: 'REPORT', @@ -149,6 +151,46 @@ const buildReportDateSettingsFn = () => { return reportDateSettings; }; +const buildOrgUnitSettingsFn = () => { + const orgUnitComponent = + withCalculateMessages(overrideMessagePropNames)( + withFocusSaver()( + withDefaultFieldContainer()( + withDefaultShouldUpdateInterface()( + withLabel({ + onGetUseVerticalOrientation: (props: Object) => props.formHorizontal, + onGetCustomFieldLabeClass: (props: Object) => `${props.fieldOptions.fieldLabelMediaBasedClass} ${labelTypeClasses.orgUnitLabel}`, + })( + withDisplayMessages()( + withInternalChangeHandler()( + withFilterProps(defaultFilterProps)(SingleOrgUnitSelectField), + ), + ), + ), + ), + ), + ), + ); + + const orgUnitSettings = { + getComponent: () => orgUnitComponent, + getComponentProps: (props: Object) => createComponentProps(props, { + width: props && props.formHorizontal ? 150 : 350, + label: i18n.t('Organisation unit'), + required: true, + }), + getPropName: () => 'orgUnit', + getValidatorContainers: () => getOrgUnitValidatorContainers(), + getMeta: () => ({ + placement: placements.TOP, + section: dataEntrySectionNames.BASICINFO, + }), + }; + + return orgUnitSettings; +}; + + const buildScheduleDateSettingsFn = () => { const scheduleDateComponent = innerProps => withCalculateMessages(overrideMessagePropNames)( @@ -360,7 +402,8 @@ const AOCFieldBuilderHOC = withAOCFieldBuilder({})(withDataEntryFields(getCatego const CleanUpHOC = withCleanUp()(AOCFieldBuilderHOC); const GeometryField = withDataEntryFieldIfApplicable(buildGeometrySettingsFn())(CleanUpHOC); const ScheduleDateField = withDataEntryField(buildScheduleDateSettingsFn())(GeometryField); -const ReportDateField = withDataEntryField(buildReportDateSettingsFn())(ScheduleDateField); +const OrgUnitField = withDataEntryField(buildOrgUnitSettingsFn())(ScheduleDateField); +const ReportDateField = withDataEntryField(buildReportDateSettingsFn())(OrgUnitField); const SaveableDataEntry = withSaveHandler(saveHandlerConfig)(withMainButton()(ReportDateField)); const CancelableDataEntry = withCancelButton(getCancelOptions)(SaveableDataEntry); const CompletableDataEntry = withDataEntryField(buildCompleteFieldSettingsFn())(CancelableDataEntry); From edf234546251ed6d7f4cfbe2038cde04b40ae4cf Mon Sep 17 00:00:00 2001 From: henrikmv Date: Wed, 5 Feb 2025 15:14:22 +0100 Subject: [PATCH 02/15] fix: change order for org unit and schedule date --- .../WidgetEventSchedule.component.js | 70 +++++++++++-------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js b/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js index a86780b8c4..c8ac1d6555 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js @@ -2,6 +2,7 @@ import React, { type ComponentType, useEffect } from 'react'; import { spacersNum } from '@dhis2/ui'; import withStyles from '@material-ui/core/styles/withStyles'; +import { DividerHorizontal as Divider } from 'capture-ui'; import i18n from '@dhis2/d2-i18n'; import { isValidOrgUnit } from 'capture-core-utils/validators/form'; import { DataSection } from '../DataSection'; @@ -15,11 +16,17 @@ import { CategoryOptions } from './CategoryOptions/CategoryOptions.component'; import { Assignee } from './Assignee'; import { ScheduleOrgUnit } from './ScheduleOrgUnit/ScheduleOrgUnit.component'; -const styles = () => ({ +const styles = theme => ({ wrapper: { paddingLeft: spacersNum.dp16, minWidth: '300px', }, + evenNumbersRecords: { + backgroundColor: theme.palette.grey.lightest, + }, + divider: { + backgroundColor: theme.palette.dividerForm, + }, }); const WidgetEventSchedulePlain = ({ @@ -76,12 +83,6 @@ const WidgetEventSchedulePlain = ({ dataTest="schedule-section" sectionName={i18n.t('Schedule info')} > - + +
+ +
- {programCategory && - - } + { + programCategory && + + + } - {enableUserAssignment && ( - - - - )} + { + enableUserAssignment && ( + + + + ) + } - - + + ); }; From 3b75a4ac58d66f4e1d10c880dd52e83e78abdce7 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Wed, 5 Feb 2025 15:21:27 +0100 Subject: [PATCH 03/15] feat: top bar org unit in read only mode --- .../components/Pages/EnrollmentEditEvent/TopBar.container.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core_modules/capture-core/components/Pages/EnrollmentEditEvent/TopBar.container.js b/src/core_modules/capture-core/components/Pages/EnrollmentEditEvent/TopBar.container.js index e613228db2..8b6355df32 100644 --- a/src/core_modules/capture-core/components/Pages/EnrollmentEditEvent/TopBar.container.js +++ b/src/core_modules/capture-core/components/Pages/EnrollmentEditEvent/TopBar.container.js @@ -65,6 +65,7 @@ export const TopBar = ({ onResetOrgUnitId={() => resetOrgUnitId()} isUserInteractionInProgress={isUserInteractionInProgress} onStartAgain={() => reset()} + isReadOnly > Date: Sat, 8 Feb 2025 13:10:44 +0100 Subject: [PATCH 04/15] fix: code clean up and topbar fix --- .../EnrollmentEditEvent/TopBar.container.js | 2 +- .../EditEventDataEntry.component.js | 86 +++++++++---------- .../WidgetEventSchedule.component.js | 46 +++++----- 3 files changed, 65 insertions(+), 69 deletions(-) diff --git a/src/core_modules/capture-core/components/Pages/EnrollmentEditEvent/TopBar.container.js b/src/core_modules/capture-core/components/Pages/EnrollmentEditEvent/TopBar.container.js index 8b6355df32..238bf0f811 100644 --- a/src/core_modules/capture-core/components/Pages/EnrollmentEditEvent/TopBar.container.js +++ b/src/core_modules/capture-core/components/Pages/EnrollmentEditEvent/TopBar.container.js @@ -65,7 +65,7 @@ export const TopBar = ({ onResetOrgUnitId={() => resetOrgUnitId()} isUserInteractionInProgress={isUserInteractionInProgress} onStartAgain={() => reset()} - isReadOnly + isReadOnly={mode === dataEntryKeys.EDIT} > { return reportDateSettings; }; -const buildOrgUnitSettingsFn = () => { - const orgUnitComponent = - withCalculateMessages(overrideMessagePropNames)( - withFocusSaver()( - withDefaultFieldContainer()( - withDefaultShouldUpdateInterface()( - withLabel({ - onGetUseVerticalOrientation: (props: Object) => props.formHorizontal, - onGetCustomFieldLabeClass: (props: Object) => `${props.fieldOptions.fieldLabelMediaBasedClass} ${labelTypeClasses.orgUnitLabel}`, - })( - withDisplayMessages()( - withInternalChangeHandler()( - withFilterProps(defaultFilterProps)(SingleOrgUnitSelectField), - ), - ), - ), - ), - ), - ), - ); - - const orgUnitSettings = { - getComponent: () => orgUnitComponent, - getComponentProps: (props: Object) => createComponentProps(props, { - width: props && props.formHorizontal ? 150 : 350, - label: i18n.t('Organisation unit'), - required: true, - }), - getPropName: () => 'orgUnit', - getValidatorContainers: () => getOrgUnitValidatorContainers(), - getMeta: () => ({ - placement: placements.TOP, - section: dataEntrySectionNames.BASICINFO, - }), - }; - - return orgUnitSettings; -}; - - const buildScheduleDateSettingsFn = () => { const scheduleDateComponent = innerProps => withCalculateMessages(overrideMessagePropNames)( @@ -239,6 +199,46 @@ const buildScheduleDateSettingsFn = () => { return scheduleDateSettings; }; +const buildOrgUnitSettingsFn = () => { + const orgUnitComponent = + withCalculateMessages(overrideMessagePropNames)( + withFocusSaver()( + withDefaultFieldContainer()( + withDefaultShouldUpdateInterface()( + withLabel({ + onGetUseVerticalOrientation: (props: Object) => props.formHorizontal, + onGetCustomFieldLabeClass: (props: Object) => `${props.fieldOptions.fieldLabelMediaBasedClass} ${labelTypeClasses.orgUnitLabel}`, + })( + withDisplayMessages()( + withInternalChangeHandler()( + withFilterProps(defaultFilterProps)(SingleOrgUnitSelectField), + ), + ), + ), + ), + ), + ), + ); + + const orgUnitSettings = { + getComponent: () => orgUnitComponent, + getComponentProps: (props: Object) => createComponentProps(props, { + width: props && props.formHorizontal ? 150 : 350, + label: i18n.t('Organisation unit'), + required: true, + }), + getPropName: () => 'orgUnit', + getValidatorContainers: () => getOrgUnitValidatorContainers(), + getMeta: () => ({ + placement: placements.TOP, + section: dataEntrySectionNames.BASICINFO, + }), + }; + + return orgUnitSettings; +}; + + const pointComponent = withCalculateMessages(overrideMessagePropNames)( withFocusSaver()( withDefaultFieldContainer()( @@ -401,9 +401,9 @@ const saveHandlerConfig = { const AOCFieldBuilderHOC = withAOCFieldBuilder({})(withDataEntryFields(getCategoryOptionsSettingsFn())(DataEntry)); const CleanUpHOC = withCleanUp()(AOCFieldBuilderHOC); const GeometryField = withDataEntryFieldIfApplicable(buildGeometrySettingsFn())(CleanUpHOC); -const ScheduleDateField = withDataEntryField(buildScheduleDateSettingsFn())(GeometryField); -const OrgUnitField = withDataEntryField(buildOrgUnitSettingsFn())(ScheduleDateField); -const ReportDateField = withDataEntryField(buildReportDateSettingsFn())(OrgUnitField); +const OrgUnitField = withDataEntryField(buildOrgUnitSettingsFn())(GeometryField); +const ScheduleDateField = withDataEntryField(buildScheduleDateSettingsFn())(OrgUnitField); +const ReportDateField = withDataEntryField(buildReportDateSettingsFn())(ScheduleDateField); const SaveableDataEntry = withSaveHandler(saveHandlerConfig)(withMainButton()(ReportDateField)); const CancelableDataEntry = withCancelButton(getCancelOptions)(SaveableDataEntry); const CompletableDataEntry = withDataEntryField(buildCompleteFieldSettingsFn())(CancelableDataEntry); diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js b/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js index c8ac1d6555..1cf0c14a9d 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/WidgetEventSchedule.component.js @@ -102,22 +102,20 @@ const WidgetEventSchedulePlain = ({ /> - { - programCategory && - - - } + {programCategory && + + } - { - enableUserAssignment && ( - - - - ) - } + {enableUserAssignment && ( + + + + )} - - + + ); }; From 649beec162945d56108fd8e89b8f1af8b561a344 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Thu, 13 Feb 2025 16:56:06 +0100 Subject: [PATCH 05/15] feat: auto select org unit --- .../DataEntry/editEventDataEntry.actions.js | 12 ++++++++-- .../ViewEventDataEntry.component.js | 2 +- .../viewEventDataEntry.actions.js | 22 +++++++++++-------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/editEventDataEntry.actions.js b/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/editEventDataEntry.actions.js index 503a47524d..b4b6f38444 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/editEventDataEntry.actions.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/editEventDataEntry.actions.js @@ -9,8 +9,11 @@ import { updateRulesEffects, } from '../../../rules'; import { RenderFoundation, Program } from '../../../metaData'; -import { getEventDateValidatorContainers } from './fieldValidators/eventDate.validatorContainersGetter'; -import { getCategoryOptionsValidatorContainers } from './fieldValidators/categoryOptions.validatorContainersGetter'; +import { + getEventDateValidatorContainers, + getOrgUnitValidatorContainers, + getCategoryOptionsValidatorContainers, +} from './fieldValidators'; import { getConvertGeometryIn, convertGeometryOut, @@ -110,6 +113,11 @@ export const openEventForEditInDataEntry = ({ type: 'DATE', validatorContainers: getEventDateValidatorContainers(), }, + { + id: 'orgUnit', + type: 'ORGANISATION_UNIT', + validatorContainers: getOrgUnitValidatorContainers(), + }, { clientId: 'geometry', dataEntryId: 'geometry', diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/ViewEventDataEntry/ViewEventDataEntry.component.js b/src/core_modules/capture-core/components/WidgetEventEdit/ViewEventDataEntry/ViewEventDataEntry.component.js index eed050d621..ffdff870ac 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/ViewEventDataEntry/ViewEventDataEntry.component.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/ViewEventDataEntry/ViewEventDataEntry.component.js @@ -150,7 +150,7 @@ const buildOrgUnitSettingsFn = () => { label: i18n.t('Organisation unit'), valueConverter: value => dataElement.convertValue(value, valueConvertFn), }), - getPropName: () => 'orgUnitId', + getPropName: () => 'orgUnit', getMeta: () => ({ placement: placements.TOP, section: dataEntrySectionNames.BASICINFO, 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 65b90ecf13..9811655061 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, effectActions } from '@dhis2/rules-engine-javascript'; +import { effectActions } from '@dhis2/rules-engine-javascript'; import { actionCreator } from '../../../actions/actions.utils'; import type { RenderFoundation, Program } from '../../../metaData'; import { getConvertGeometryIn, convertGeometryOut, convertStatusOut } from '../../DataEntries'; @@ -51,7 +51,7 @@ export const loadViewEventDataEntry = serverMinorVersion, }: { eventContainer: ClientEventContainer, - orgUnit: OrgUnit, + orgUnit: Object, foundation: RenderFoundation, program: Program, dataEntryId: string, @@ -67,15 +67,15 @@ export const loadViewEventDataEntry = type: 'DATE', validatorContainers: getEventDateValidatorContainers(), }, - { - id: 'orgUnitId', - type: 'ORGANISATION_UNIT', - validatorContainers: getOrgUnitValidatorContainers(), - }, { id: 'scheduledAt', type: 'DATE', }, + { + id: 'orgUnit', + type: 'ORGANISATION_UNIT', + validatorContainers: getOrgUnitValidatorContainers(), + }, { clientId: 'geometry', dataEntryId: 'geometry', @@ -118,6 +118,11 @@ export const loadViewEventDataEntry = dataEntryPropsToInclude.push(...Object.keys(attributeCategoryOptions).map(id => ({ id, type: 'TEXT' }))); } + const clientValuesForDataEntry = { + ...eventContainer.event, + orgUnit: { id: orgUnit.id, name: orgUnit.name, path: orgUnit.path }, + }; + const extraProps = { eventId: eventContainer.event.eventId, }; @@ -126,7 +131,7 @@ export const loadViewEventDataEntry = loadEditDataEntryAsync( dataEntryId, dataEntryKey, - eventContainer.event, + clientValuesForDataEntry, eventContainer.values, dataEntryPropsToInclude, foundation, @@ -163,7 +168,6 @@ export const loadViewEventDataEntry = }); } const filteredEffects = filterApplicableRuleEffects(effects, effectActions.ASSIGN_VALUE); - return [ ...dataEntryActions, updateRulesEffects(filteredEffects, formId), From 20391e19e3e2dae25d9f197068eab52626853a9c Mon Sep 17 00:00:00 2001 From: henrikmv Date: Fri, 14 Feb 2025 13:21:53 +0100 Subject: [PATCH 06/15] feat: convert org unit in server data --- .../mainConverters/mainEventClientToServerConverter.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js b/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js index 25d5042c43..d89ce4a763 100644 --- a/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js +++ b/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js @@ -7,6 +7,7 @@ import { convertEventAttributeOptions } from '../convertEventAttributeOptions'; const keysToSkip = { completedAt: 'completedAt', completedBy: 'completedBy', + orgUnitId: 'orgUnitId', }; export function convertMainEventClientToServer(event: Object, serverMinorVersion: number) { @@ -14,7 +15,6 @@ export function convertMainEventClientToServer(event: Object, serverMinorVersion eventId: 'event', programId: 'program', programStageId: 'programStage', - orgUnitId: 'orgUnit', trackedEntityId: 'trackedEntity', enrollmentId: 'enrollment', assignee: 'assignedUser', @@ -32,6 +32,9 @@ export function convertMainEventClientToServer(event: Object, serverMinorVersion case 'assignee': convertedValue = value && convertClientToServer(value, dataElementTypes.ASSIGNEE); break; + case 'orgUnit': + convertedValue = value && convertClientToServer(value, dataElementTypes.ORGANISATION_UNIT); + break; default: convertedValue = value; break; From bf2c473ccac5391d90509657d1a560147719dd0f Mon Sep 17 00:00:00 2001 From: henrikmv Date: Fri, 14 Feb 2025 14:50:05 +0100 Subject: [PATCH 07/15] feat: rules --- .../epics/editEventDataEntry.epics.js | 22 +++++++++---------- .../capture-core/rules/rules.types.js | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/epics/editEventDataEntry.epics.js b/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/epics/editEventDataEntry.epics.js index 6ff85dc625..8faa384940 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/epics/editEventDataEntry.epics.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/DataEntry/epics/editEventDataEntry.epics.js @@ -4,7 +4,6 @@ import { from } from 'rxjs'; import { ofType } from 'redux-observable'; import { map, switchMap } from 'rxjs/operators'; import { batchActions } from 'redux-batched-actions'; -import type { OrgUnit } from '@dhis2/rules-engine-javascript'; import { rulesExecutedPostUpdateField } from '../../../DataEntry/actions/dataEntry.actions'; import { batchActionTypes as editEventDataEntryBatchActionTypes, @@ -26,13 +25,13 @@ import { getDataEntryKey } from '../../../DataEntry/common/getDataEntryKey'; import { prepareEnrollmentEventsForRulesEngine } from '../../../../events/prepareEnrollmentEvents'; import { getEnrollmentForRulesEngine, getAttributeValuesForRulesEngine } from '../../helpers'; import type { QuerySingleResource } from '../../../../utils/api'; +import { getCoreOrgUnitFn, orgUnitFetched } from '../../../../metadataRetrieval/coreOrgUnit'; const runRulesForEditSingleEvent = async ({ store, dataEntryId, itemId, uid, - orgUnit, fieldData, programId, querySingleResource, @@ -42,7 +41,6 @@ const runRulesForEditSingleEvent = async ({ itemId: string, uid: string, programId: string, - orgUnit: OrgUnit, fieldData?: ?FieldData, querySingleResource: QuerySingleResource }) => { @@ -66,6 +64,10 @@ const runRulesForEditSingleEvent = async ({ // $FlowFixMe const currentEvent = { ...currentEventValues, ...currentEventMainData, eventId }; + const { coreOrgUnit, cached } = + // $FlowFixMe + await getCoreOrgUnitFn(querySingleResource)(currentEvent.orgUnit?.id, store.value.organisationUnits); + let effects; if (program instanceof TrackerProgram) { const { enrollment, attributeValues } = state.enrollmentDomain; @@ -82,7 +84,7 @@ const runRulesForEditSingleEvent = async ({ effects = getApplicableRuleEffectsForTrackerProgram({ program, stage, - orgUnit, + orgUnit: coreOrgUnit, currentEvent: { ...currentEvent, createdAt: apiCurrentEventOriginal.createdAt }, otherEvents: prepareEnrollmentEventsForRulesEngine(apiOtherEvents), enrollmentData: getEnrollmentForRulesEngine(enrollment), @@ -91,7 +93,7 @@ const runRulesForEditSingleEvent = async ({ } else { effects = getApplicableRuleEffectsForEventProgram({ program, - orgUnit, + orgUnit: coreOrgUnit, currentEvent, }); } @@ -105,6 +107,7 @@ const runRulesForEditSingleEvent = async ({ return batchActions([ updateRulesEffects(effectsWithValidations, formId), rulesExecutedPostUpdateField(dataEntryId, itemId, uid), + ...(coreOrgUnit && !cached ? [orgUnitFetched(coreOrgUnit)] : []), ], editEventDataEntryBatchActionTypes.RULES_EFFECTS_ACTIONS_BATCH); }; @@ -114,20 +117,19 @@ export const runRulesOnUpdateDataEntryFieldForEditSingleEventEpic = ( store: ReduxStore, { querySingleResource }: ApiUtils, ) => -// $FlowSuppress + // $FlowSuppress action$.pipe( ofType(editEventDataEntryBatchActionTypes.UPDATE_DATA_ENTRY_FIELD_EDIT_SINGLE_EVENT_ACTION_BATCH), map(actionBatch => actionBatch.payload.find(action => action.type === editEventDataEntryActionTypes.START_RUN_RULES_ON_UPDATE), ), switchMap((action) => { - const { dataEntryId, itemId, uid, orgUnit, programId } = action.payload; + const { dataEntryId, itemId, uid, programId } = action.payload; const runRulesForEditSingleEventPromise = runRulesForEditSingleEvent({ store, dataEntryId, itemId, uid, - orgUnit, programId, querySingleResource, }); @@ -139,7 +141,7 @@ export const runRulesOnUpdateFieldForEditSingleEventEpic = ( store: ReduxStore, { querySingleResource }: ApiUtils, ) => -// $FlowSuppress + // $FlowSuppress action$.pipe( ofType(editEventDataEntryBatchActionTypes.UPDATE_FIELD_EDIT_SINGLE_EVENT_ACTION_BATCH), map(actionBatch => @@ -153,7 +155,6 @@ export const runRulesOnUpdateFieldForEditSingleEventEpic = ( dataEntryId, itemId, uid, - orgUnit, programId, } = action.payload; const fieldData: FieldData = { @@ -166,7 +167,6 @@ export const runRulesOnUpdateFieldForEditSingleEventEpic = ( dataEntryId, itemId, uid, - orgUnit, fieldData, programId, querySingleResource, diff --git a/src/core_modules/capture-core/rules/rules.types.js b/src/core_modules/capture-core/rules/rules.types.js index 07f870ae4b..b2c7f8e9e9 100644 --- a/src/core_modules/capture-core/rules/rules.types.js +++ b/src/core_modules/capture-core/rules/rules.types.js @@ -24,7 +24,7 @@ export type GetApplicableRuleEffectsForTrackerProgramInput = {| export type GetApplicableRuleEffectsForEventProgramInput = {| program: EventProgram, - orgUnit: OrgUnit, + orgUnit: ?OrgUnit, currentEvent?: EventData, |}; From fa768ec46da783e55b78b513172721f3363e0b99 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Mon, 17 Feb 2025 17:06:50 +0100 Subject: [PATCH 08/15] fix: top bar event program --- .../components/Pages/ViewEvent/TopBar.container.js | 4 +++- .../components/Pages/ViewEvent/ViewEventPage.component.js | 4 +++- .../components/Pages/ViewEvent/ViewEventPage.container.js | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/TopBar.container.js b/src/core_modules/capture-core/components/Pages/ViewEvent/TopBar.container.js index 4aeef7fbcb..52444b359b 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/TopBar.container.js +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/TopBar.container.js @@ -11,7 +11,6 @@ import { resetCategoryOption, resetAllCategoryOptions, } from './ViewEventPage.actions'; - import { TopBarActions } from '../../TopBarActions'; type TopBarProps = { @@ -19,6 +18,7 @@ type TopBarProps = { programId?: string, orgUnitId?: string, selectedCategories?: any, + isReadOnly: boolean, formIsOpen: boolean, }; @@ -26,6 +26,7 @@ export const TopBar = ({ programId, orgUnitId, selectedCategories, + isReadOnly, isUserInteractionInProgress, formIsOpen, }: TopBarProps) => { @@ -63,6 +64,7 @@ export const TopBar = ({ isUserInteractionInProgress={isUserInteractionInProgress} formIsOpen={formIsOpen} onStartAgain={() => reset()} + isReadOnly={isReadOnly} > { +export const ViewEventPageComponent = ({ isUserInteractionInProgress, showAddRelationship, isReadOnly }: Props) => { const { serverVersion: { minor } } = useConfig(); useEffect(() => inMemoryFileStore.clear, []); @@ -29,6 +30,7 @@ export const ViewEventPageComponent = ({ isUserInteractionInProgress, showAddRel programId={programId} orgUnitId={orgUnitId} selectedCategories={selectedCategories} + isReadOnly={isReadOnly} isUserInteractionInProgress={isUserInteractionInProgress} formIsOpen /> diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventPage.container.js b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventPage.container.js index e7ae0841d8..0e8ec24d10 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventPage.container.js +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventPage.container.js @@ -7,6 +7,7 @@ import { withLoadingIndicator, withErrorMessageHandler } from '../../../HOC'; const mapStateToProps = (state: ReduxState) => { const eventDetailsSection = state.viewEventPage.eventDetailsSection || {}; + const isReadOnly = eventDetailsSection.showEditEvent const isUserInteractionInProgress = (state.currentSelections.complete && eventDetailsSection.showEditEvent) ? @@ -17,6 +18,7 @@ const mapStateToProps = (state: ReduxState) => { error: state.activePage.viewEventLoadError && state.activePage.viewEventLoadError.error, ready: !state.activePage.lockedSelectorLoads, isUserInteractionInProgress, + isReadOnly, showAddRelationship: state.viewEventPage.showAddRelationship, }; }; From 464b5e75c075639eadd31136c9bb79bb95aa32c1 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Mon, 17 Feb 2025 17:10:24 +0100 Subject: [PATCH 09/15] fix: missing semi colon --- .../components/Pages/ViewEvent/ViewEventPage.container.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventPage.container.js b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventPage.container.js index 0e8ec24d10..6b494e9485 100644 --- a/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventPage.container.js +++ b/src/core_modules/capture-core/components/Pages/ViewEvent/ViewEventPage.container.js @@ -7,7 +7,7 @@ import { withLoadingIndicator, withErrorMessageHandler } from '../../../HOC'; const mapStateToProps = (state: ReduxState) => { const eventDetailsSection = state.viewEventPage.eventDetailsSection || {}; - const isReadOnly = eventDetailsSection.showEditEvent + const isReadOnly = eventDetailsSection.showEditEvent; const isUserInteractionInProgress = (state.currentSelections.complete && eventDetailsSection.showEditEvent) ? From cdbcbf65bde3bce1e6919c76b861b98f094e0eed Mon Sep 17 00:00:00 2001 From: henrikmv Date: Mon, 17 Feb 2025 17:47:52 +0100 Subject: [PATCH 10/15] fix: style change --- .../EditEventDataEntry/EditEventDataEntry.component.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 16820b11f8..6f458afc51 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 @@ -207,7 +207,8 @@ const buildOrgUnitSettingsFn = () => { withDefaultShouldUpdateInterface()( withLabel({ onGetUseVerticalOrientation: (props: Object) => props.formHorizontal, - onGetCustomFieldLabeClass: (props: Object) => `${props.fieldOptions.fieldLabelMediaBasedClass} ${labelTypeClasses.orgUnitLabel}`, + onGetCustomFieldLabeClass: (props: Object) => + `${props.fieldOptions.fieldLabelMediaBasedClass} ${labelTypeClasses.dateLabel}`, })( withDisplayMessages()( withInternalChangeHandler()( From d49df9d6958967333f9a90fd89c0d328c7a0358e Mon Sep 17 00:00:00 2001 From: henrikmv Date: Wed, 19 Feb 2025 15:17:07 +0100 Subject: [PATCH 11/15] fix: review comment --- .../EditEventDataEntry/editEventDataEntry.epics.js | 1 + .../mainConverters/mainEventClientToServerConverter.js | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) 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 dcd813f546..1aed4b98c9 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 @@ -121,6 +121,7 @@ export const saveEditedEventEpic = (action$: InputObservable, store: ReduxStore, const serverData = { events: [{ ...mainDataServerValues, + orgUnit: mainDataServerValues.orgUnit.id, attributeOptionCombo: undefined, dataValues: formFoundation .getElements() diff --git a/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js b/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js index d89ce4a763..25d5042c43 100644 --- a/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js +++ b/src/core_modules/capture-core/events/mainConverters/mainEventClientToServerConverter.js @@ -7,7 +7,6 @@ import { convertEventAttributeOptions } from '../convertEventAttributeOptions'; const keysToSkip = { completedAt: 'completedAt', completedBy: 'completedBy', - orgUnitId: 'orgUnitId', }; export function convertMainEventClientToServer(event: Object, serverMinorVersion: number) { @@ -15,6 +14,7 @@ export function convertMainEventClientToServer(event: Object, serverMinorVersion eventId: 'event', programId: 'program', programStageId: 'programStage', + orgUnitId: 'orgUnit', trackedEntityId: 'trackedEntity', enrollmentId: 'enrollment', assignee: 'assignedUser', @@ -32,9 +32,6 @@ export function convertMainEventClientToServer(event: Object, serverMinorVersion case 'assignee': convertedValue = value && convertClientToServer(value, dataElementTypes.ASSIGNEE); break; - case 'orgUnit': - convertedValue = value && convertClientToServer(value, dataElementTypes.ORGANISATION_UNIT); - break; default: convertedValue = value; break; From a2ba1f7fda6667a5807cb85c76b5f83a8180e318 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Thu, 20 Feb 2025 09:06:32 +0100 Subject: [PATCH 12/15] fix: add path to org unit type --- packages/rules-engine/src/rulesEngine.types.js | 1 + .../ViewEventDataEntry/viewEventDataEntry.actions.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rules-engine/src/rulesEngine.types.js b/packages/rules-engine/src/rulesEngine.types.js index fd25b9e251..bb7b071ce0 100644 --- a/packages/rules-engine/src/rulesEngine.types.js +++ b/packages/rules-engine/src/rulesEngine.types.js @@ -144,6 +144,7 @@ export type OrgUnitGroup = $ReadOnly<{| export type OrgUnit = $ReadOnly<{ id: string, name: string, + path?: string, code: string, groups: Array, }>; 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 9811655061..bec42c4463 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 { effectActions } 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'; @@ -51,7 +51,7 @@ export const loadViewEventDataEntry = serverMinorVersion, }: { eventContainer: ClientEventContainer, - orgUnit: Object, + orgUnit: OrgUnit, foundation: RenderFoundation, program: Program, dataEntryId: string, From 2ad2a3fe0ab2a16f08f5ae722d9f052550ac87d9 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Thu, 20 Feb 2025 11:51:19 +0100 Subject: [PATCH 13/15] fix: breaking test --- .../EditEventDataEntry/editEventDataEntry.epics.js | 1 + 1 file changed, 1 insertion(+) 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 1aed4b98c9..b3cbc9a4af 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 @@ -268,6 +268,7 @@ export const saveEventAndCompleteEnrollmentEpic = (action$: InputObservable, sto const editEvent = { ...mainDataServerValues, + orgUnit: mainDataServerValues.orgUnit.id, attributeOptionCombo: undefined, dataValues: formFoundation .getElements() From d41e9aea9091a68a606ab74734f8c02fedfb73e2 Mon Sep 17 00:00:00 2001 From: henrikmv Date: Fri, 21 Feb 2025 10:44:12 +0100 Subject: [PATCH 14/15] fix: type for org unit rules engine --- packages/rules-engine/src/rulesEngine.types.js | 1 - .../ViewEventDataEntry/viewEventDataEntry.actions.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/rules-engine/src/rulesEngine.types.js b/packages/rules-engine/src/rulesEngine.types.js index bb7b071ce0..fd25b9e251 100644 --- a/packages/rules-engine/src/rulesEngine.types.js +++ b/packages/rules-engine/src/rulesEngine.types.js @@ -144,7 +144,6 @@ export type OrgUnitGroup = $ReadOnly<{| export type OrgUnit = $ReadOnly<{ id: string, name: string, - path?: string, code: string, groups: Array, }>; 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 bec42c4463..96a7fbd365 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 @@ -51,7 +51,7 @@ export const loadViewEventDataEntry = serverMinorVersion, }: { eventContainer: ClientEventContainer, - orgUnit: OrgUnit, + orgUnit: { ...OrgUnit, path: string }, foundation: RenderFoundation, program: Program, dataEntryId: string, From 8170e396713b9b75ea78147dd22175550f0dcfcc Mon Sep 17 00:00:00 2001 From: henrikmv Date: Fri, 21 Feb 2025 18:14:35 +0100 Subject: [PATCH 15/15] fix: org unit for geometry --- .../EditEventDataEntry/EditEventDataEntry.component.js | 7 +++++-- .../EditEventDataEntry/EditEventDataEntry.container.js | 2 ++ 2 files changed, 7 insertions(+), 2 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 6f458afc51..5fed499194 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 @@ -295,7 +295,7 @@ const buildGeometrySettingsFn = () => ({ label: i18n.t('Area'), dialogLabel: i18n.t('Area'), required: false, - orgUnitId: props.orgUnit?.id, + orgUnitId: props.orgUnitIdFieldValue, }); } return createComponentProps(props, { @@ -303,7 +303,7 @@ const buildGeometrySettingsFn = () => ({ label: i18n.t('Coordinate'), dialogLabel: i18n.t('Coordinate'), required: false, - orgUnitId: props.orgUnit?.id, + orgUnitId: props.orgUnitIdFieldValue, }); }, getPropName: () => 'geometry', @@ -442,6 +442,7 @@ type Props = { enrollmentId?: string, isCompleted?: boolean, assignee?: UserFormField | null, + orgUnitFieldValue: ?OrgUnit, }; @@ -537,6 +538,7 @@ class EditEventDataEntryPlain extends Component { dataEntryId, orgUnit, programId, + orgUnitFieldValue, onUpdateDataEntryField, onUpdateField, onStartAsyncUpdateField, @@ -556,6 +558,7 @@ class EditEventDataEntryPlain extends Component { onSaveAndCompleteEnrollment={onSaveAndCompleteEnrollment(orgUnit)} fieldOptions={this.fieldOptions} dataEntrySections={this.dataEntrySections} + orgUnitIdFieldValue={orgUnitFieldValue?.id} orgUnit={orgUnit} orgUnitId={orgUnit?.id} programId={programId} diff --git a/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.container.js b/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.container.js index 23f9599d56..fff2ffeb41 100644 --- a/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.container.js +++ b/src/core_modules/capture-core/components/WidgetEventEdit/EditEventDataEntry/EditEventDataEntry.container.js @@ -32,12 +32,14 @@ const mapStateToProps = (state: ReduxState, props) => { const itemId = state.dataEntries[props.dataEntryId] && state.dataEntries[props.dataEntryId].itemId; const dataEntryKey = `${props.dataEntryId}-${itemId}`; + const orgUnitFieldValue = state.dataEntriesFieldsValue[dataEntryKey]?.orgUnit; const isCompleted = state.dataEntriesFieldsValue[dataEntryKey]?.complete === 'true'; return { ready: !state.activePage.isDataEntryLoading && !eventDetailsSection.loading, itemId, isCompleted, + orgUnitFieldValue, enrolledAt: state.enrollmentDomain?.enrollment?.enrolledAt, occurredAt: state.enrollmentDomain?.enrollment?.occurredAt, eventData: state.enrollmentDomain?.enrollment?.events,