Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
f2f36de
feat: add custom plural for note relationship attribute
henrikmv Jul 23, 2026
18351e9
feat: update name assignment in TrackedEntityTypeFactory to use trans…
henrikmv Jul 23, 2026
5a895cd
feat: metadata loading support custom plural labels based on server v…
henrikmv Jul 23, 2026
8cedb68
feat: add customTerminologyPlurals feature support
henrikmv Jul 23, 2026
433aa56
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-21878…
henrikmv Jul 25, 2026
03ae46b
feat: single source for changelog data
henrikmv Aug 5, 2026
ef3f2ed
fix: (review) devin comments temp
henrikmv Aug 5, 2026
d8449fb
feat: simplify imports for removeEventChangelogQueries and refactor f…
henrikmv Aug 5, 2026
93c4649
fix: clean up
henrikmv Aug 6, 2026
ab2685d
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-21878…
henrikmv Aug 6, 2026
c479953
fix: separate base and plural fields for improved readability
henrikmv Aug 6, 2026
e5b4d74
feat: temp change helper function and stop capitalize
henrikmv Aug 7, 2026
302cc2b
feat: implement custom terminology handling with bootstrap
henrikmv Aug 7, 2026
823f4e1
fix: revert changes belonging to child branch
henrikmv Aug 7, 2026
764e73b
fix: sonar qube
henrikmv Aug 7, 2026
df95c4d
Merge remote-tracking branch 'origin/master' into hv/feat/DHIS2-21635…
henrikmv Aug 7, 2026
2e19a93
feat: code clean up
henrikmv Aug 7, 2026
0a0d90a
fix: type change
henrikmv Aug 7, 2026
809aad6
feat: update terminology
henrikmv Aug 7, 2026
54d8332
feat: enhance API program fields with custom terminology support
henrikmv Aug 7, 2026
45eb553
feat: clean up
henrikmv Aug 7, 2026
14966a4
Merge remote-tracking branch 'origin/hv/feat/DHIS2-21655_uncomplete-e…
henrikmv Aug 12, 2026
de452bc
feat: temp devin review
henrikmv Aug 12, 2026
6a8cd9c
fix: revert single event infrastructure
henrikmv Aug 12, 2026
56ac556
feat: update terminology handling across components
henrikmv Aug 12, 2026
718ae46
feat: enhance custom terminology handling and optimize location query…
henrikmv Aug 12, 2026
b52ffd8
feat: custom terminology context handling
henrikmv Aug 12, 2026
f3b34dc
fix: change approach
henrikmv Aug 12, 2026
2b92b9a
fix: complete clean up after revert
henrikmv Aug 12, 2026
d66e422
feat: update custom label handling and refactor label exports
henrikmv Aug 12, 2026
762f6bd
fix: correct capitalization in widget header and improve label resolu…
henrikmv Aug 12, 2026
ee3d687
fix: simplify label resolution logic by removing fallback for plural …
henrikmv Aug 13, 2026
e28f271
feat: integrate event changelog query removal in bulk completion actions
henrikmv Aug 13, 2026
8b7afbb
feat: new translate function
henrikmv Aug 15, 2026
542e611
Merge remote-tracking branch 'origin/master' into hv/chore/DHIS2-2196…
henrikmv Aug 15, 2026
0396218
Merge branch 'hv/feat/DHIS2-21655_uncomplete-event-view-mode' into hv…
henrikmv Aug 15, 2026
2cc3bcc
Merge remote-tracking branch 'origin/hv/feat/DHIS2-21655_uncomplete-e…
henrikmv Aug 17, 2026
ad9b50a
Merge remote-tracking branch 'origin/master' into hv/chore/DHIS2-2196…
henrikmv Aug 17, 2026
64911b5
Merge branch 'hv/feat/DHIS2-21655_uncomplete-event-view-mode' into hv…
henrikmv Aug 17, 2026
3c0b707
feat: clean up
henrikmv Aug 17, 2026
1d004db
Merge branch 'hv/feat/DHIS2-21655_uncomplete-event-view-mode' into hv…
henrikmv Aug 17, 2026
87aab24
fix: allign type annotations for useSelector in EventDetailsSection
henrikmv Aug 17, 2026
1f52f72
Merge remote-tracking branch 'origin/hv/feat/DHIS2-21655_uncomplete-e…
henrikmv Aug 18, 2026
2544e26
Merge branch 'hv/feat/DHIS2-21655_uncomplete-event-view-mode' into hv…
henrikmv Aug 21, 2026
0e7edfa
Merge branch 'hv/feat/DHIS2-21655_uncomplete-event-view-mode' into hv…
henrikmv Aug 21, 2026
7be3fad
Merge branch 'hv/feat/DHIS2-21655_uncomplete-event-view-mode' into hv…
henrikmv Aug 22, 2026
fc1dc99
Merge branch 'hv/feat/DHIS2-21655_uncomplete-event-view-mode' into hv…
henrikmv Aug 28, 2026
89b75c7
fix: temp clean up
henrikmv Aug 28, 2026
a2dd40f
feat: replace tLabel with tCustomTerm
henrikmv Aug 28, 2026
cb9b195
feat: consolidate capitalizeFirstLetter utility and update imports
henrikmv Aug 31, 2026
3ead8dd
fix: simplify interpolation handling in tCustomTerm function
henrikmv Aug 31, 2026
d00b1b9
fix: update plural label fallback to use singular label for default
henrikmv Sep 1, 2026
3a4a73f
Merge remote-tracking branch 'origin/hv/chore/DHIS2-21969_refine-conf…
henrikmv Sep 1, 2026
8a222e2
Revert "Merge remote-tracking branch 'origin/hv/chore/DHIS2-21969_ref…
henrikmv Sep 1, 2026
e43e81b
Merge branch 'hv/feat/DHIS2-21655_uncomplete-event-view-mode' into hv…
henrikmv Sep 8, 2026
d314e2e
Merge branch 'hv/feat/DHIS2-21655_uncomplete-event-view-mode' into hv…
henrikmv Sep 8, 2026
d807b5e
fix: remove duplicate import of enrollmentStatuses in CompletionMenuItem
henrikmv Sep 8, 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
4 changes: 2 additions & 2 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-08T15:17:29.259Z\n"
"PO-Revision-Date: 2026-09-08T15:17:29.262Z\n"
"POT-Creation-Date: 2026-09-08T15:49:17.652Z\n"
"PO-Revision-Date: 2026-09-08T15:49:17.653Z\n"

msgid "The application could not be loaded."
msgstr "The application could not be loaded."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import React from 'react';
import i18n from '@dhis2/d2-i18n';
import log from 'loglevel';
import { MenuItem, IconCheckmark16, IconUndo16 } from '@dhis2/ui';
import { useMutation } from '@tanstack/react-query';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useAlert, useDataEngine } from '@dhis2/app-runtime';
import { useDispatch } from 'react-redux';
import { errorCreator } from 'capture-core-utils';
import { statusTypes as eventStatuses } from 'capture-core/events/statusTypes';
import { CompleteModal } from '../../DataEntries/common/trackerEvent/withAskToCompleteEnrollment/CompleteModal';
import { removeEventChangelogQueries } from '../../WidgetsChangelog';
import { statusTypes as enrollmentStatuses } from '../../../enrollment';
import { CompleteModal } from '../../DataEntries/common/trackerEvent/withAskToCompleteEnrollment/CompleteModal';
import {
updateEnrollmentAndEvents,
commitEnrollmentAndEvents,
Expand Down Expand Up @@ -64,6 +65,7 @@ export const CompletionMenuItem = ({
onAskCompleteEnrollment,
}: MenuItemProps) => {
const dataEngine = useDataEngine();
const queryClient = useQueryClient();
const { show: showError } = useAlert(({ message }) => message, { critical: true });

const isCompleted = eventStatus === eventStatuses.COMPLETED;
Expand All @@ -78,7 +80,10 @@ export const CompletionMenuItem = ({
log.error(errorCreator('An error occurred when updating event status')({ error, eventId, newStatus }));
onError?.();
},
onSuccess: () => onSuccess?.(newStatus),
onSuccess: () => {
removeEventChangelogQueries(queryClient, eventId);
onSuccess?.(newStatus);
},
},
);

Expand Down Expand Up @@ -122,6 +127,7 @@ export const CompleteMenuItemModal = ({
}: ModalProps) => {
const dataEngine = useDataEngine();
const dispatch = useDispatch();
const queryClient = useQueryClient();
const { show: showError } = useAlert(({ message }) => message, { critical: true });

const handleError = (error: unknown) => {
Expand All @@ -134,7 +140,10 @@ export const CompleteMenuItemModal = ({
{
onMutate: () => onMutate?.(eventStatuses.COMPLETED),
onError: (error) => { handleError(error); onError?.(); },
onSuccess: () => onSuccess?.(eventStatuses.COMPLETED),
onSuccess: () => {
removeEventChangelogQueries(queryClient, eventId);
onSuccess?.(eventStatuses.COMPLETED);
},
},
);

Expand Down Expand Up @@ -165,6 +174,7 @@ export const CompleteMenuItemModal = ({
},
onSuccess: () => {
dispatch(commitEnrollmentAndEvents());
removeEventChangelogQueries(queryClient, eventId);
onSuccess?.(eventStatuses.COMPLETED);
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { errorCreator } from 'capture-core-utils';
import { formatMomentEn } from 'capture-core-utils/date';
import { useDispatch, useSelector } from 'react-redux';
import { useTimeZoneConversion } from '@dhis2/app-runtime';
import { useQueryClient } from '@tanstack/react-query';
import type { ApiEnrollmentEvent } from 'capture-core-utils/types/api-types';
import { removeEventChangelogQueries } from '../../../WidgetsChangelog';
import {
commitEnrollmentAndEvents,
EnrollmentAccessProvider,
Expand Down Expand Up @@ -50,6 +52,7 @@ import { useHideWidgetByRuleLocations } from '../../../../hooks';
export const EnrollmentPageDefault = () => {
const { navigate } = useNavigate();
const dispatch = useDispatch();
const queryClient = useQueryClient();
const { fromClientDate } = useTimeZoneConversion();
const { status: widgetEnrollmentStatus } = useSelector(({ widgetEnrollment }: any) => widgetEnrollment);
const { enrollmentId, programId, teiId, orgUnitId } = useLocationQuery();
Expand Down Expand Up @@ -181,7 +184,8 @@ export const EnrollmentPageDefault = () => {
);
const onUpdateEnrollmentStatusSuccess = useCallback(() => {
dispatch(commitEnrollmentAndEvents());
}, [dispatch]);
removeEventChangelogQueries(queryClient);
}, [dispatch, queryClient]);

const onBackToMainPage = useCallback(() => {
navigate(`/?${buildUrlQueryString({ orgUnitId, programId })}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ import { DataStoreKeyByPage, useEnrollmentPageLayout } from '../common/Enrollmen
import { DefaultPageLayout } from './PageLayout/DefaultPageLayout.constants';
import { rollbackAssignee, setAssignee } from './EnrollmentEditEventPage.actions';
import { convertClientToServer, convertServerToClient } from '../../../converters';
import { CHANGELOG_ENTITY_TYPES } from '../../WidgetsChangelog';
import { ReactQueryAppNamespace } from '../../../utils/reactQueryHelpers';
import { removeEventChangelogQueries } from '../../WidgetsChangelog';
import { statusTypes } from '../../../enrollment';
import { cancelEditEventDataEntry } from '../../WidgetEventEdit/EditEventDataEntry/editEventDataEntry.actions';
import { setCurrentDataEntry } from '../../DataEntry/actions/dataEntry.actions';
Expand Down Expand Up @@ -246,8 +245,7 @@ const EnrollmentEditEventPageWithContextPlain = ({
}, [dispatch, navigate, orgUnitId, enrollmentId, eventId]);

const onSaveExternal = useCallback(() => {
const queryKey = [ReactQueryAppNamespace, 'changelog', CHANGELOG_ENTITY_TYPES.EVENT, eventId];
queryClient.removeQueries(queryKey);
removeEventChangelogQueries(queryClient, eventId);
navigate(`enrollment?${buildUrlQueryString({ orgUnitId, enrollmentId })}`);
}, [navigate, orgUnitId, enrollmentId, eventId, queryClient]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import { useCoreOrgUnit } from '../../../../metadataRetrieval/coreOrgUnit';
import { NoticeBox } from '../../../NoticeBox';
import { EventChangelogWrapper } from '../../../WidgetEventEdit/EventChangelogWrapper';
import { OverflowButton } from '../../../Buttons';
import { ReactQueryAppNamespace } from '../../../../utils/reactQueryHelpers';
import { CHANGELOG_ENTITY_TYPES } from '../../../WidgetsChangelog';
import { removeEventChangelogQueries } from '../../../WidgetsChangelog';
import { useCategoryCombinations } from '../../../DataEntryDhis2Helpers/AOC/useCategoryCombinations';
import { useMetadataForProgramStage } from '../../../DataEntries/common/ProgramStage/useMetadataForProgramStage';
import { useProgramExpiryForUser, useEventEditPermissions } from '../../../../hooks';
Expand Down Expand Up @@ -64,7 +63,6 @@ const EventDetailsSectionPlain = (props: PlainProps & { classes: any }) => {
const {
classes,
eventId,
eventData,
onOpenEditEvent,
isEditEventPage,
programStage,
Expand All @@ -74,7 +72,9 @@ const EventDetailsSectionPlain = (props: PlainProps & { classes: any }) => {
showEditButton,
...passOnProps
} = props;
const orgUnitId = useSelector((state: any) => state.viewEventPage.loadedValues?.orgUnit?.id);
const orgUnitId = useSelector((state: { viewEventPage: { loadedValues: any } }) =>
state.viewEventPage.loadedValues?.orgUnit?.id);
const loadedValues = useSelector((state: { viewEventPage: { loadedValues: any } }) => state.viewEventPage.loadedValues);
const { formFoundation } = useMetadataForProgramStage({ programId });
const { orgUnit, error } = useCoreOrgUnit(orgUnitId);
const { programCategory, isLoading } = useCategoryCombinations(programId);
Expand All @@ -85,14 +85,13 @@ const EventDetailsSectionPlain = (props: PlainProps & { classes: any }) => {
const { canToggleCompletion } = useEventEditPermissions({
programId,
stage: programStage,
eventStatus: eventData?.eventContainer?.event?.status,
occurredAtClient: convertFormToClient(eventData?.dataEntryValues?.occurredAt, dataElementTypes.DATE) as string,
completedAtClient: eventData?.eventContainer?.event?.completedAt,
eventStatus: loadedValues?.eventContainer?.event?.status,
occurredAtClient: convertFormToClient(loadedValues?.dataEntryValues?.occurredAt, dataElementTypes.DATE) as string,
completedAtClient: loadedValues?.eventContainer?.event?.completedAt,
});

const onSaveExternal = useCallback(() => {
const queryKey = [ReactQueryAppNamespace, 'changelog', CHANGELOG_ENTITY_TYPES.EVENT, eventId];
queryClient.removeQueries(queryKey);
removeEventChangelogQueries(queryClient, eventId);
onBackToAllEvents();
}, [eventId, queryClient, onBackToAllEvents]);

Expand Down Expand Up @@ -190,7 +189,6 @@ const EventDetailsSectionPlain = (props: PlainProps & { classes: any }) => {
<EventChangelogWrapper
isOpen
setIsOpen={setChangeLogIsOpen}
eventData={eventData?.eventContainer?.values}
eventId={eventId}
formFoundation={programStage.stageForm}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
const mapStateToProps = (state: any, ownProps: any) => ({
isEditEventPage: state.viewEventPage.eventDetailsSection && state.viewEventPage.eventDetailsSection.showEditEvent,
eventId: state.viewEventPage.eventId,
eventData: state.viewEventPage.loadedValues || {},
programId: state.currentSelections.programId,
...ownProps,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { ProgramStage } from 'capture-core/metaData';
export type PlainProps = {
isEditEventPage?: boolean;
eventId: string;
eventData: any;
onOpenEditEvent: (orgUnit: any, programCategory?: any) => void;
programStage: ProgramStage;
eventAccess: { read: boolean, write: boolean };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { dataElementTypes } from '../../../metaData';
import type { Props } from './EventChangelogWrapper.types';
import { WidgetEventChangelog } from '../../WidgetsChangelog';

export const EventChangelogWrapper = ({ formFoundation, eventId, eventData, ...passOnProps }: Props) => {
export const EventChangelogWrapper = ({ formFoundation, eventId, ...passOnProps }: Props) => {
const dataItemDefinitions = useMemo(() => {
const elements = formFoundation.getElements();
const contextLabels = formFoundation.getLabels();
Expand Down Expand Up @@ -62,7 +62,6 @@ export const EventChangelogWrapper = ({ formFoundation, eventId, eventData, ...p
<WidgetEventChangelog
{...passOnProps}
eventId={eventId}
eventData={eventData}
dataItemDefinitions={dataItemDefinitions}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ type PassOnProps = {

export type Props = PassOnProps & {
formFoundation: RenderFoundation,
eventData: Record<string, unknown>,
};
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ const WidgetEventEditPlain = ({
const { currentPageMode } = useEnrollmentEditEventPageMode(eventStatus);
const [changeLogIsOpen, setChangeLogIsOpen] = useState(false);
// "Edit event"-button depends on loadedValues. Delay rendering component until loadedValues has been initialized.
const loadedValues = useSelector((state: { viewEventPage: { loadedValues: any } }) => state.viewEventPage.loadedValues);
const loadedValues = useSelector((state: any) => state.viewEventPage.loadedValues);
const orgUnit = loadedValues?.orgUnit;
const occurredAt = loadedValues?.dataEntryValues?.occurredAt;
const completedAt = loadedValues?.eventContainer?.event?.completedAt;
Expand Down Expand Up @@ -205,7 +205,6 @@ const WidgetEventEditPlain = ({
isOpen
setIsOpen={setChangeLogIsOpen}
eventId={loadedValues.eventContainer.id}
eventData={loadedValues.eventContainer.values}
formFoundation={formFoundation}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ export const TrackedEntityChangelogWrapper = ({
close={() => setIsOpen(false)}
programId={programAPI.id}
dataItemDefinitions={dataItemDefinitions}
trackedEntityData={transformedTrackedEntityData}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ import {
useTeiDisplayName,
} from './hooks';
import { DataEntry, dataEntryActionTypes, TEI_MODAL_STATE, convertClientToView } from './DataEntry';
import { ReactQueryAppNamespace } from '../../utils/reactQueryHelpers';
import { CHANGELOG_ENTITY_TYPES } from '../WidgetsChangelog';
import { removeTrackedEntityChangelogQueries } from '../WidgetsChangelog';
import { OverflowMenu } from './OverflowMenu';
import {
useDataEntryFormConfig,
Expand Down Expand Up @@ -142,7 +141,7 @@ const WidgetProfilePlain = ({
}), [clientAttributesWithSubvalues]);

const onSaveExternal = useCallback(() => {
queryClient.removeQueries([ReactQueryAppNamespace, 'changelog', CHANGELOG_ENTITY_TYPES.TRACKED_ENTITY, teiId]);
removeTrackedEntityChangelogQueries(queryClient, teiId);
}, [queryClient, teiId]);

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import {
MenuItem,
IconRedo16,
} from '@dhis2/ui';
import { useMutation } from '@tanstack/react-query';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useAlert, useDataEngine } from '@dhis2/app-runtime';
import { errorCreator } from 'capture-core-utils';
import type { ApiEnrollmentEvent } from 'capture-core-utils/types/api-types';
import { statusTypes as eventStatuses } from 'capture-core/events/statusTypes';
import { removeEventChangelogQueries } from '../../../../../../WidgetsChangelog';
import { DirectionalArrow } from '../../../../../../../utils/rtl';

type Props = {
Expand All @@ -28,6 +29,7 @@ export const SkipAction = ({
onUpdateEventStatus,
}: Props) => {
const dataEngine = useDataEngine();
const queryClient = useQueryClient();
const { show: showError } = useAlert(
({ message }) => message,
{ critical: true },
Expand Down Expand Up @@ -55,6 +57,9 @@ export const SkipAction = ({

return { previousStatus };
},
onSuccess: () => {
removeEventChangelogQueries(queryClient, eventId);
},
onError: (error: unknown, payload: { status: string }, context?: { previousStatus: string }) => {
showError({ message: i18n.t('An error occurred when updating event status') });
log.error(errorCreator('An error occurred when updating event status')({ error, payload, context }));
Expand All @@ -75,7 +80,7 @@ export const SkipAction = ({
icon={<IconRedo16 />}
label={i18n.t('Unskip')}
onClick={() => handleMenuItemClick(eventStatuses.SCHEDULE)}
suffix=""
suffix={null}
/>
);
}
Expand All @@ -86,7 +91,7 @@ export const SkipAction = ({
icon={<DirectionalArrow />}
label={i18n.t('Skip')}
onClick={() => handleMenuItemClick(eventStatuses.SKIPPED)}
suffix=""
suffix={null}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,20 @@ import { Changelog, CHANGELOG_ENTITY_TYPES } from '../common/Changelog';

type Props = {
eventId: string;
eventData: Record<string, unknown>;
dataItemDefinitions: ItemDefinitions;
isOpen: boolean;
setIsOpen: (value: boolean | ((prev: boolean) => boolean)) => void;
};

export const WidgetEventChangelog = ({
eventId,
eventData,
setIsOpen,
...passOnProps
}: Props) => (
<Changelog
{...passOnProps}
close={() => setIsOpen(false)}
entityId={eventId}
entityData={eventData}
entityType={CHANGELOG_ENTITY_TYPES.EVENT}
/>
);
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,17 @@ type Props = {
dataItemDefinitions: ItemDefinitions;
isOpen: boolean;
close: () => void;
trackedEntityData: Record<string, unknown>;
};

export const WidgetTrackedEntityChangelog = ({
teiId,
programId,
close,
trackedEntityData,
...passOnProps
}: Props) => (
<Changelog
{...passOnProps}
close={close}
entityData={trackedEntityData}
entityId={teiId}
programId={programId}
entityType={CHANGELOG_ENTITY_TYPES.TRACKED_ENTITY}
Expand Down
Loading
Loading