Skip to content

Commit

Permalink
feat: [DHIS2-11836] respect block entry form (#3759)
Browse files Browse the repository at this point in the history
* feat: respect block entry form

* feat: respect block entry form and authorities

* fix: tooltip

* feat: cypress test for disabled edit event button

* fix: set tracker auto test restricted

* fix: cypress test

* feat: cy test for disabled button
  • Loading branch information
henrikmv authored Aug 28, 2024
1 parent 6ab9393 commit ed3ed5a
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ Scenario: User can see disabled scheduled date for active event
Then the user see the following text: Enrollment: Edit Event
Then the user see the schedule date field with tooltip: Scheduled date cannot be changed for Active events

@user:trackerAutoTestRestricted
Scenario: The user cannot enter edit mode for completed events
Given you land on the enrollment event page with selected Person by having typed /#/enrollmentEventEdit?eventId=nUVwTLuQ6FT&orgUnitId=DiszpKrYNg8
And the user see the following text: Enrollment: View Event
Then the edit button should be disabled

Scenario: User can edit the event and complete the enrollment
Given you land on the enrollment event page with selected Malaria Entity by having typed #/enrollmentEventEdit?eventId=MHR4Zj6KLz0&orgUnitId=DiszpKrYNg8
And the enrollment status is active
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,9 @@ And('you open the Birth stage event', () => {
});
});

Then('the edit button should be disabled', () => {
cy.get('[data-test="widget-enrollment-event"]')
.find('[data-test="dhis2-uicore-button"]')
.eq(1)
.should('be.disabled');
});
3 changes: 3 additions & 0 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,9 @@ msgstr "Scheduled date cannot be changed for {{ eventStatus }} events"
msgid "Event completed"
msgstr "Event completed"

msgid "The event cannot be edited after it has been completed"
msgstr "The event cannot be edited after it has been completed"

msgid "Back to all stages and events"
msgstr "Back to all stages and events"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import { OverflowButton } from '../Buttons';
import { EventChangelogWrapper } from './EventChangelogWrapper';
import { FEATURES, useFeature } from '../../../capture-core-utils';
import { inMemoryFileStore } from '../DataEntry/file/inMemoryFileStore';
import { eventStatuses } from './constants/status.const';
import { useAuthorities } from './hooks';

const styles = {
header: {
Expand Down Expand Up @@ -99,6 +101,14 @@ export const WidgetEventEditPlain = ({
const loadedValues = useSelector(({ viewEventPage }) => viewEventPage.loadedValues);

const eventAccess = getProgramEventAccess(programId, stageId);
const { canEditCompletedEvent } = useAuthorities();
const blockEntryForm = stage.blockEntryForm && !canEditCompletedEvent && eventStatus === eventStatuses.COMPLETED;
const disableEdit = !eventAccess?.write || blockEntryForm;

const tooltipContent = blockEntryForm ?
i18n.t('The event cannot be edited after it has been completed') :
i18n.t('You don\'t have access to edit this event');

const availableProgramStages = useAvailableProgramStages(stage, teiId, enrollmentId, programId);
const { programCategory } = useCategoryCombinations(programId);
if (error) {
Expand All @@ -117,14 +127,14 @@ export const WidgetEventEditPlain = ({
{currentPageMode === dataEntryKeys.VIEW && (
<div className={classes.menuActions}>
<ConditionalTooltip
content={i18n.t('You don\'t have access to edit this event')}
enabled={!eventAccess?.write}
content={tooltipContent}
enabled={disableEdit}
wrapperClassName={classes.tooltip}
>
<Button
small
secondary
disabled={!eventAccess?.write}
disabled={disableEdit}
icon={<IconEdit24 />}
onClick={() => dispatch(startShowEditEventDataEntry(orgUnit, programCategory))}
>
Expand Down Expand Up @@ -225,3 +235,4 @@ export const WidgetEventEditPlain = ({
) : <LoadingMaskElementCenter />;
};
export const WidgetEventEdit: ComponentType<ComponentProps> = withStyles(styles)(WidgetEventEditPlain);

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @flow

export const eventStatuses = Object.freeze({
ACTIVE: 'ACTIVE',
COMPLETED: 'COMPLETED',
VISITED: 'VISITED',
SCHEDULE: 'SCHEDULE',
OVERDUE: 'OVERDUE',
SKIPPED: 'SKIPPED',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// @flow
export { useAuthorities } from './useAuthorities';
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// @flow
import { useApiMetadataQuery } from 'capture-core/utils/reactQueryHelpers';

const auth = Object.freeze({
F_UNCOMPLETE_EVENT: 'F_UNCOMPLETE_EVENT',
ALL: 'ALL',
});

export const useAuthorities = () => {
const queryKey = ['authorities'];
const queryFn = {
resource: 'me.json',
params: {
fields: 'authorities',
},
};
const queryOptions = {
select: ({ authorities }) =>
authorities &&
authorities.some(authority => authority === auth.ALL || authority === auth.F_UNCOMPLETE_EVENT),
};
const { data } = useApiMetadataQuery<any>(queryKey, queryFn, queryOptions);

return {
canEditCompletedEvent: Boolean(data),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export class ProgramStage {
_id: string;
_name: string;
_access: { data: { write: boolean } };
_blockEntryForm: boolean;
_untranslatedName: string;
_stageForm: RenderFoundation;
_relationshipTypes: Array<RelationshipType>;
Expand Down Expand Up @@ -41,6 +42,14 @@ export class ProgramStage {
this._stageForm = stageForm;
}

get blockEntryForm(): boolean {
return this._blockEntryForm;
}

set blockEntryForm(blockEntryForm: boolean) {
this._blockEntryForm = blockEntryForm;
}

get id(): string {
return this._id;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ export class ProgramStageFactory {
_stage.generatedByEnrollmentDate = !!cachedProgramStage.generatedByEnrollmentDate;
_stage.reportDateToUse = cachedProgramStage.reportDateToUse;
_stage.minDaysFromStart = cachedProgramStage.minDaysFromStart;
_stage.blockEntryForm = !!cachedProgramStage.blockEntryForm;
_stage.repeatable = cachedProgramStage.repeatable;
_stage.stageForm = new RenderFoundation((_form) => {
_form.id = cachedProgramStage.id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const fieldsParam = 'id,displayName,displayShortName,description,programType,sty
'categoryCombo[id,displayName,isDefault,categories[id,displayName]],' +
'userRoles[id,displayName],' +
// eslint-disable-next-line max-len
'programStages[id,access,autoGenerateEvent,openAfterEnrollment,hideDueDate,allowGenerateNextVisit,remindCompleted,repeatable,generatedByEnrollmentDate,reportDateToUse,minDaysFromStart,name,displayName,description,displayExecutionDateLabel,displayDueDateLabel,formType,featureType,validationStrategy,enableUserAssignment,style,dataEntryForm[id,htmlCode]' +
'programStages[id,access,autoGenerateEvent,openAfterEnrollment,hideDueDate,allowGenerateNextVisit,remindCompleted,repeatable,generatedByEnrollmentDate,reportDateToUse,blockEntryForm,minDaysFromStart,name,displayName,description,displayExecutionDateLabel,displayDueDateLabel,formType,featureType,validationStrategy,enableUserAssignment,style,dataEntryForm[id,htmlCode]' +
'programStageSections[id,displayName,displayDescription,sortOrder,dataElements[id]],' +
// eslint-disable-next-line max-len
'programStageDataElements[compulsory,displayInReports,renderOptionsAsRadio,allowFutureDate,renderType[*],dataElement[id]]]' +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export type CachedDataEntryForm = {
export type CachedProgramStage = {
id: string,
access: Object,
blockEntryForm: boolean,
name: string,
displayName: string,
description: ?string,
Expand Down

0 comments on commit ed3ed5a

Please sign in to comment.