Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
199cb0e
fix: update orgUnit type to allow null and enhance form value handling
henrikmv Aug 18, 2026
9948583
fix: add teiOrgUnit to WidgetProfile
henrikmv Aug 18, 2026
603c072
fix: add rule effects handling in widget profile
henrikmv Aug 18, 2026
dc3d671
fix: handle orgUnit as nullable and enforce orgUnitId requirement in …
henrikmv Aug 18, 2026
1df2b60
fix: replace orgUnitId with waitForOrgUnit in useFormValues and useLi…
henrikmv Aug 18, 2026
fcc8079
fix: integrate rule effects handling
henrikmv Aug 18, 2026
45c023f
fix: prevent flashing of hidden attributes by delaying rendering unti…
henrikmv Aug 18, 2026
2054d1b
Merge remote-tracking branch 'origin/hv/fix/DHIS2-21937_profile-widge…
henrikmv Aug 18, 2026
26f691d
Revert "Merge remote-tracking branch 'origin/hv/fix/DHIS2-21937_profi…
henrikmv Aug 18, 2026
3de9aa2
fix: remove orgUnit dependency from rule effects condition
henrikmv Aug 18, 2026
379e914
fix: refactor enrollment data handling and improve rule effects valid…
henrikmv Aug 18, 2026
3f73b20
fix: update translation for hidden attributes message and improve typ…
henrikmv Aug 19, 2026
bcbb388
fix: update loading state computation to handle undefined rule effects
henrikmv Aug 19, 2026
cb4807a
fix: update loading state computation to include ruleEffectsPending
henrikmv Aug 19, 2026
c3b6947
fix: update orgUnitId prop to use effectiveOrgUnitId in EnrollmentPag…
henrikmv Aug 19, 2026
46a43ee
fix: update orgUnitId usage and improve loading state computation in …
henrikmv Aug 20, 2026
d80110f
fix: clean up
henrikmv Aug 20, 2026
a986d71
fix: clean up by reverting old changes
henrikmv Aug 20, 2026
2fe73d5
fix: update translations and improve loading state handling in Widget…
henrikmv Aug 20, 2026
89ddcf9
fix: add missing org unit gard
henrikmv Aug 20, 2026
de622b4
fix: add programOwnerId to useCommonEnrollmentDomainData
henrikmv Aug 20, 2026
bf2ea63
fix: handle programOwnerOrgUnit error
henrikmv Aug 21, 2026
b49aa3d
fix: require orgUnitId
henrikmv Aug 21, 2026
c979f3b
Merge branch 'master' into hv/fix/DHIS2-18620_hidden-TEA-displayed-in…
henrikmv Aug 21, 2026
d85b5c8
fix: (review) rename orgUnitId to programOwnerId across DataEntry and…
henrikmv Aug 25, 2026
85a39ac
feat: refactor rule effects handling to use enrollment scope
henrikmv Aug 26, 2026
7044c91
fix: clean up
henrikmv Aug 26, 2026
b75282e
fix: hide progam stage bug
henrikmv Aug 26, 2026
87952fd
Merge branch 'master' into hv/fix/DHIS2-18620_hidden-TEA-displayed-in…
henrikmv Aug 26, 2026
f21ee94
fix: (review) remove unused rule effects logic and types
henrikmv Sep 1, 2026
ea9238b
fix: (review) update condition in useEffect to prevent unnecessary di…
henrikmv Sep 1, 2026
459b0b0
fix: align edit profile modal rule engine input with other scopes
henrikmv Sep 3, 2026
401801c
Merge branch 'master' into hv/fix/DHIS2-18620_hidden-TEA-displayed-in…
henrikmv Sep 3, 2026
3d172a9
fix: revert and splitt fixes into two tickets
henrikmv Sep 8, 2026
f91e5bb
fix: (review) refactor enrollment rule effects handling
henrikmv Sep 9, 2026
9f4da42
fix: (review) add ruleEffectsPending to stop hidden fields from flashing
henrikmv Sep 9, 2026
ac0d150
fix: (review) remove unused force parameter
henrikmv Sep 9, 2026
ab1bb04
fix: replace useFilteredWidgetData with direct selector for enrollmen…
henrikmv Sep 9, 2026
64e3a49
fix: add updateEnrollmentProgramOwner action and integrate with owner…
henrikmv Sep 9, 2026
51ad336
fix: remove unused getUseNameForOptionSet function and its references
henrikmv Sep 9, 2026
e6a3f13
fix: rename programOwnerId to ownerOrgUnitId across components and ac…
henrikmv Sep 9, 2026
17d4c23
fix: move isEmptyList declaration to a single location for clarity
henrikmv Sep 10, 2026
3cff0d6
fix: (review) add initial run skip logic for enrollment rule effects
henrikmv Sep 10, 2026
801d966
Merge branch 'master' into hv/fix/DHIS2-18620_hidden-TEA-displayed-in…
henrikmv Sep 11, 2026
d567887
fix: merge conflict in pot file
henrikmv Sep 11, 2026
0457b8e
Merge branch 'master' into hv/fix/DHIS2-18620_hidden-TEA-displayed-in…
henrikmv Sep 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2026-09-11T09:39:26.174Z\n"
"PO-Revision-Date: 2026-09-11T09:39:26.174Z\n"
"POT-Creation-Date: 2026-09-10T09:13:28.812Z\n"
"PO-Revision-Date: 2026-09-10T09:13:28.812Z\n"

msgid "The application could not be loaded."
msgstr "The application could not be loaded."
Expand Down Expand Up @@ -1697,12 +1697,12 @@ msgstr "View profile"
msgid "Profile widget could not be loaded. Please try again later"
msgstr "Profile widget could not be loaded. Please try again later"

msgid "No attributes configured for {{trackedEntityTypeName}}"
msgstr "No attributes configured for {{trackedEntityTypeName}}"

msgid "No attributes configured"
msgstr "No attributes configured"

msgid "No attributes configured to display"
msgstr "No attributes configured to display"

msgid "{{trackedEntityTypeName}} profile"
msgstr "{{trackedEntityTypeName}} profile"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
updateEnrollmentDate,
updateIncidentDate,
useCommonEnrollmentDomainData,
useRuleEffects,
useEnrollmentScopeRuleEffects,
selectEnrollmentWidgetEffects,
} from '../../common/EnrollmentOverviewDomain';
import {
deleteEnrollment,
Expand All @@ -28,7 +29,6 @@ import { useCoreOrgUnit } from '../../../../metadataRetrieval/coreOrgUnit';
import { DataStoreKeyByPage, EnrollmentPageLayout } from '../../common/EnrollmentOverviewDomain/EnrollmentPageLayout';
import { useProgramMetadata, useProgramStages } from './hooks';
import { useNavigate, buildUrlQueryString, useLocationQuery } from '../../../../utils/routing';
import { useFilteredWidgetData } from './hooks/useFilteredWidgetData';
import { useLinkedRecordClick } from '../../common/TEIRelationshipsWidget';
import {
useEnrollmentPageLayout,
Expand All @@ -53,7 +53,6 @@ export const EnrollmentPageDefault = () => {
const { fromClientDate } = useTimeZoneConversion();
const { status: widgetEnrollmentStatus } = useSelector(({ widgetEnrollment }: any) => widgetEnrollment);
const { enrollmentId, programId, teiId, orgUnitId } = useLocationQuery();
const { orgUnit, error } = useCoreOrgUnit(orgUnitId);
const { onLinkedRecordClick } = useLinkedRecordClick();
const {
pageLayout,
Expand All @@ -64,13 +63,15 @@ export const EnrollmentPageDefault = () => {
dataStoreKey: DataStoreKeyByPage.ENROLLMENT_OVERVIEW,
});

const program = useTrackerProgram(programId);
const {
error: enrollmentsError,
enrollment,
attributeValues,
readOnly: trackedEntityInactive,
ownerOrgUnitId,
} = useCommonEnrollmentDomainData(teiId, enrollmentId, programId);
const program = useTrackerProgram(programId);
const { orgUnit: ownerOrgUnit, error: ownerOrgUnitError } = useCoreOrgUnit(ownerOrgUnitId);

const onStatusToggleSuccess = useCallback(() => {
dispatch(setTrackedEntityInactiveStatus(!trackedEntityInactive));
Expand All @@ -87,20 +88,21 @@ export const EnrollmentPageDefault = () => {
https://dhis2.atlassian.net/browse/DHIS2-17574
*/

if (programMetaDataError || enrollmentsError) {
if (programMetaDataError || enrollmentsError || ownerOrgUnitError) {
log.error(errorCreator('Enrollment page could not be loaded')(
{ programMetaDataError, enrollmentsError },
{ programMetaDataError, enrollmentsError, ownerOrgUnitError },
));
}

const ruleEffects = useRuleEffects({
orgUnit,
useEnrollmentScopeRuleEffects({
enrollmentId,
orgUnit: ownerOrgUnit,
program,
apiEnrollment: enrollment,
apiAttributeValues: attributeValues,
});

const outputEffects = useFilteredWidgetData(ruleEffects);
const outputEffects = useSelector(selectEnrollmentWidgetEffects);
const hideWidgets = useHideWidgetByRuleLocations(program.programRules);

const onDeleteTrackedEntitySuccess = useCallback(() => {
Expand Down Expand Up @@ -193,10 +195,6 @@ export const EnrollmentPageDefault = () => {
);
}

if (error) {
return error?.errorComponent;
}

return (
<EnrollmentAccessProvider program={program} trackedEntityInactive={trackedEntityInactive}>
<EnrollmentPageLayout
Expand All @@ -205,6 +203,7 @@ export const EnrollmentPageDefault = () => {
availableWidgets={WidgetsForEnrollmentPageDefault}
teiId={teiId}
orgUnitId={orgUnitId}
ownerOrgUnitId={ownerOrgUnitId}
program={program}
stages={stages}
events={enrollment?.events}
Expand All @@ -230,7 +229,6 @@ export const EnrollmentPageDefault = () => {
onUpdateEnrollmentStatus={onUpdateEnrollmentStatus}
onUpdateEnrollmentStatusSuccess={onUpdateEnrollmentStatusSuccess}
onUpdateEnrollmentStatusError={onUpdateEnrollmentStatusError}
ruleEffects={ruleEffects}
widgetEnrollmentStatus={widgetEnrollmentStatus}
onAccessLostFromTransfer={onAccessLostFromTransfer}
feedbackEmptyText={i18n.t('No feedback for this enrollment yet')}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { effectActions } from '@dhis2/rules-engine-javascript';
import type { TrackerProgram } from 'capture-core/metaData';
import type { HideWidgets, WidgetEffects } from '../../common/EnrollmentOverviewDomain';
import type { Event } from '../../common/EnrollmentOverviewDomain/useCommonEnrollmentDomainData';
Expand Down Expand Up @@ -44,7 +43,6 @@ export type Props = {
onUpdateEnrollmentStatus: (enrollment: any) => void;
onUpdateEnrollmentStatusSuccess: (params?: { redirect?: boolean }) => void;
onUpdateEnrollmentStatusError: (message: string) => void;
ruleEffects?: Array<{id: string; type: keyof typeof effectActions}>;
widgetEnrollmentStatus?: string | null;
pageLayout: PageLayoutConfig;
availableWidgets: Readonly<{ [key: string]: WidgetConfig }>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React, { useState, useMemo, ComponentType } from 'react';
import { useSelector } from 'react-redux';
import i18n from '@dhis2/d2-i18n';
import { colors, spacers, IconAdd16, IconCalendar16 } from '@dhis2/ui';
import { withStyles, WithStyles } from 'capture-core-utils/styles';
import type { OutputEffect } from '@dhis2/rules-engine-javascript';
import { Widget } from '../../../../Widget';
import { QuickActionButton } from './QuickActionButton/QuickActionButton';
import { tabMode } from '../../../EnrollmentAddEvent/NewEventWorkspace/newEventWorkspace.constants';
import { useNavigate, buildUrlQueryString, useLocationQuery } from '../../../../../utils/routing';
import { useEnrollmentAccessContext } from '../../../common/EnrollmentOverviewDomain/EnrollmentAccessContext';
import { selectEnrollmentHiddenProgramStageIds } from '../../../common/EnrollmentOverviewDomain';
import { OwnProps, ProgramStage, EventCount } from './EnrollmentQuickActions.types';

const styles = {
Expand All @@ -23,14 +24,15 @@ type Props = OwnProps & WithStyles<typeof styles>;
const EnrollmentQuickActionsComponentPlain = ({
stages,
events,
ruleEffects,
classes,
}: Props) => {
const [open, setOpen] = useState<boolean>(true);
const { navigate } = useNavigate();
const { enrollmentId, programId, teiId, orgUnitId } = useLocationQuery();
const { anyStageWriteAccess } = useEnrollmentAccessContext();

const hiddenProgramStageIds = useSelector(selectEnrollmentHiddenProgramStageIds);

const stagesWithEventCount = useMemo(() => stages.map((stage) => {
const mutatedStage = { ...stage };
mutatedStage.eventCount = (events
Expand All @@ -40,21 +42,15 @@ const EnrollmentQuickActionsComponentPlain = ({
return mutatedStage;
}), [events, stages]);

const hiddenProgramStageRuleEffects = useMemo(
() => ruleEffects?.filter((ruleEffect: OutputEffect): boolean => ruleEffect.type === 'HIDEPROGRAMSTAGE'),
[ruleEffects],
);

const noStageAvailable = useMemo(
() =>
stagesWithEventCount.every(
(programStage: ProgramStage & EventCount) =>
(!programStage.dataAccess?.write) ||
(!programStage.repeatable && (programStage.eventCount ?? 0) > 0) ||
hiddenProgramStageRuleEffects
?.find((ruleEffect: OutputEffect) => ruleEffect.id === programStage.id),
Boolean(hiddenProgramStageIds?.[programStage.id]),
),
[stagesWithEventCount, hiddenProgramStageRuleEffects],
[stagesWithEventCount, hiddenProgramStageIds],
);

const onNavigationFromQuickActions = (tab: string) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { OutputEffect } from '@dhis2/rules-engine-javascript';

export type EventCount = { eventCount?: number };

export type ProgramStage = {
Expand All @@ -15,5 +13,4 @@ export type Event = { programStage: string };
export type OwnProps = {
stages: Array<ProgramStage & EventCount>;
events: Array<Event>;
ruleEffects?: Array<OutputEffect>;
};

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const EnrollmentAddEventPagePlain = ({ classes }: WithStyles<typeof styles>) =>
attributeValues,
error: commonDataError,
readOnly: trackedEntityInactive,
ownerOrgUnitId,
} = useCommonEnrollmentDomainData(teiId, enrollmentId, programId);
const { pageLayout, isLoading } = useEnrollmentPageLayout({
selectedScopeId: validIds[IdTypes.PROGRAM_ID]?.id ?? null,
Expand Down Expand Up @@ -96,9 +97,10 @@ const EnrollmentAddEventPagePlain = ({ classes }: WithStyles<typeof styles>) =>
<EnrollmentAddEventPageDefault
pageLayout={pageLayout!}
enrollment={enrollment}
attributeValues={attributeValues as Record<string, unknown> | null | undefined}
attributeValues={attributeValues}
commonDataError={Boolean(commonDataError)}
trackedEntityInactive={Boolean(trackedEntityInactive)}
ownerOrgUnitId={ownerOrgUnitId}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import {
showEnrollmentError,
updateEnrollmentAndEvents,
updateOrAddEnrollmentEvents,
useEnrollmentScopeRuleEffects,
} from '../../common/EnrollmentOverviewDomain';
import { useTrackerProgram } from '../../../../hooks/useTrackerProgram';
import { useCoreOrgUnit } from '../../../../metadataRetrieval/coreOrgUnit';
import { dataEntryHasChanges as getDataEntryHasChanges } from '../../../DataEntry/common/dataEntryHasChanges';
import type { ContainerProps } from './EnrollmentAddEventPageDefault.types';
import { WidgetsForEnrollmentEventNew } from '../PageLayout/DefaultPageLayout.constants';
Expand All @@ -34,6 +37,7 @@ export const EnrollmentAddEventPageDefault = ({
attributeValues,
commonDataError,
trackedEntityInactive,
ownerOrgUnitId,
}: ContainerProps) => {
const { programId, stageId, orgUnitId, teiId, enrollmentId } = useLocationQuery();

Expand Down Expand Up @@ -111,6 +115,16 @@ export const EnrollmentAddEventPageDefault = ({

const dataEntryHasChanges = useSelector((state: ReduxState) => getDataEntryHasChanges(state, widgetReducerName));
const { program } = useProgramInfo(programId);
const trackerProgram = useTrackerProgram(programId);
const { orgUnit: ownerOrgUnit } = useCoreOrgUnit(ownerOrgUnitId);

useEnrollmentScopeRuleEffects({
enrollmentId,
orgUnit: ownerOrgUnit,
program: trackerProgram,
apiEnrollment: enrollment ?? undefined,
apiAttributeValues: attributeValues ?? undefined,
});
const selectedProgramStage = [...program?.stages.values() ?? []].find((item: any) => item.id === stageId);
const outputEffects = useWidgetDataFromStore(widgetReducerName);
const hideWidgets = useHideWidgetByRuleLocations(program?.programRules.concat(selectedProgramStage?.programRules ?? []));
Expand Down Expand Up @@ -205,6 +219,7 @@ export const EnrollmentAddEventPageDefault = ({
onUpdateEnrollmentStatusError={onUpdateEnrollmentStatusError}
onAccessLostFromTransfer={onAccessLostFromTransfer}
trackedEntityInactive={trackedEntityInactive}
ownerOrgUnitId={ownerOrgUnitId}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ApiEnrollmentEvent } from 'capture-core-utils/types/api-types';
import type { HideWidgets, WidgetEffects } from '../../common/EnrollmentOverviewDomain';
import type { AttributeValue } from '../../common/EnrollmentOverviewDomain/useCommonEnrollmentDomainData';
import type { ExternalSaveHandler } from '../../../WidgetEnrollmentEventNew';
import type {
PageLayoutConfig,
Expand All @@ -9,6 +10,7 @@ import { Program } from '../../../../metaData';

export type Props = {
program: Program | null | undefined;
ownerOrgUnitId?: string;
stageId: string;
orgUnitId: string;
teiId: string;
Expand Down Expand Up @@ -48,7 +50,8 @@ export type ContainerProps = {
occurredAt?: string;
enrollment?: string;
} | null | undefined;
attributeValues: Record<string, unknown> | null | undefined;
attributeValues: Array<AttributeValue> | null | undefined;
commonDataError: boolean;
trackedEntityInactive: boolean;
ownerOrgUnitId?: string;
};
Loading
Loading