Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [DHIS2-17655] Two event workspace #3726

Merged
merged 22 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e03ea54
feat: add plugin functionality
eirikhaugstulen Jun 17, 2024
1b23658
Merge remote-tracking branch 'origin/master' into eh/feat/DHIS2-17591…
eirikhaugstulen Jun 18, 2024
5b5497b
chore: flow
eirikhaugstulen Jun 18, 2024
2504789
feat: support plugins in program stages
eirikhaugstulen Jun 18, 2024
e599d05
chore: flow
eirikhaugstulen Jun 18, 2024
5e96878
fix: option set logic
eirikhaugstulen Jun 19, 2024
1cb4612
fix: review
eirikhaugstulen Jun 30, 2024
c9aab55
fix: pass in cached element definitions
eirikhaugstulen Jul 1, 2024
5dd3ac6
Merge remote-tracking branch 'refs/remotes/origin/master' into eh/fea…
eirikhaugstulen Jul 1, 2024
0c446d1
chore: temp
eirikhaugstulen Jul 3, 2024
ff6e800
Merge remote-tracking branch 'refs/remotes/origin/master' into eh/fea…
eirikhaugstulen Jul 3, 2024
0ed89ce
Merge remote-tracking branch 'refs/remotes/origin/master' into eh/fea…
eirikhaugstulen Jul 9, 2024
b44e501
fix: temp
eirikhaugstulen Jul 10, 2024
4e41c05
Merge remote-tracking branch 'refs/remotes/origin/master' into eh/fea…
eirikhaugstulen Jul 15, 2024
a0e58b8
feat: add two event workspace functionality
eirikhaugstulen Jul 23, 2024
6a8e097
Merge remote-tracking branch 'refs/remotes/origin/master' into eh/fea…
eirikhaugstulen Jul 23, 2024
b25455b
feat: lint
eirikhaugstulen Jul 23, 2024
5561bd5
Merge remote-tracking branch 'refs/remotes/origin/master' into eh/fea…
eirikhaugstulen Jul 31, 2024
aea077f
feat: add subvalues
eirikhaugstulen Aug 8, 2024
ffcf09d
Merge remote-tracking branch 'refs/remotes/origin/master' into eh/fea…
eirikhaugstulen Aug 8, 2024
97d11ba
chore: remove attribute
eirikhaugstulen Aug 8, 2024
656b471
fix: add fallback for v39 and v40
eirikhaugstulen Aug 13, 2024
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
21 changes: 18 additions & 3 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ msgstr ""
"(in the same domain). Please refresh this page if you would like to use "
"this version again, but be aware that this will close other versions."

msgid "More"
msgstr "More"

msgid "View {{programName}} dashboard"
msgstr "View {{programName}} dashboard"

Expand Down Expand Up @@ -982,6 +985,12 @@ msgstr "Could not retrieve metadata. Please try again later."
msgid "The enrollment event data could not be found"
msgstr "The enrollment event data could not be found"

msgid "Loading"
msgstr "Loading"

msgid "An error occurred while loading the form"
msgstr "An error occurred while loading the form"

msgid "Possible duplicates found"
msgstr "Possible duplicates found"

Expand Down Expand Up @@ -1527,6 +1536,15 @@ msgstr "{{ scheduledEvents }} scheduled"
msgid "Stages and Events"
msgstr "Stages and Events"

msgid "An error occurred while loading the widget."
msgstr "An error occurred while loading the widget."

msgid "View linked event"
msgstr "View linked event"

msgid "Scheduled"
msgstr "Scheduled"

msgid "Changelog"
msgstr "Changelog"

Expand Down Expand Up @@ -1693,9 +1711,6 @@ msgstr "An error has occured. See log for details"
msgid "Scheduled{{ escape }} due {{ time }}"
msgstr "Scheduled{{ escape }} due {{ time }}"

msgid "Scheduled"
msgstr "Scheduled"

msgid "Overdue{{ escape }} due {{ time }}"
msgstr "Overdue{{ escape }} due {{ time }}"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @flow
import * as React from 'react';
import i18n from '@dhis2/d2-i18n';
import { useRef, useState } from 'react';
import { Button, Layer, Popper } from '@dhis2/ui';

Expand Down Expand Up @@ -42,6 +43,7 @@ export const OverflowButton = ({
return (
<div ref={anchorRef}>
<Button
aria-label={label ?? i18n.t('More')}
primary={primary}
secondary={secondary}
dataTest={dataTest}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ class D2Form extends React.PureComponent<PropsForPureComponent> {
renderHorizontal = (section: Section, passOnProps: any) => (
<D2SectionContainer
key={section.id}
innerRef={(sectionInstance) => { this.setSectionInstance(sectionInstance, section.id); }}
innerRef={(sectionInstance) => {
this.setSectionInstance(sectionInstance, section.id);
}}
sectionMetaData={section}
validationStrategy={this.props.formFoundation.validationStrategy}
formId={this.getFormId()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export class D2SectionFieldsComponent extends Component<Props> {
fieldsMetadata: metaDataElement.fields,
customAttributes: metaDataElement.customAttributes,
formId: props.formId,
viewMode: props.viewMode,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ export class FormBuilder extends React.Component<Props> {
customAttributes,
name,
formId,
viewMode,
} = field.props;

return (
Expand All @@ -578,6 +579,7 @@ export class FormBuilder extends React.Component<Props> {
pluginSource={pluginSource}
fieldsMetadata={fieldsMetadata}
formId={formId}
viewMode={viewMode}
onUpdateField={this.commitFieldUpdateFromPlugin.bind(this)}
pluginContext={pluginContext}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
export const PluginErrorMessages = Object.freeze({
SET_FIELD_VALUE_MISSING_ID: 'setFieldValue: missing required fieldId',
SET_FIELD_VALUE_ID_NOT_ALLOWED: 'setFieldValue: fieldId must be one of the configured plugin ids',
SET_CONTEXT_FIELD_VALUE_MISSING_ID: 'setContextFieldValue: tried to set value for a field that does not exist in the plugin context',
});

export const FormFieldTypes = Object.freeze({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const FormFieldPlugin = (props: ContainerProps) => {
onUpdateField,
customAttributes,
pluginContext,
viewMode = false,
} = props;
const metadataByPluginId = useMemo(() => Object.fromEntries(fieldsMetadata), [fieldsMetadata]);
const configuredPluginIds = useMemo(() => Object.keys(metadataByPluginId), [metadataByPluginId]);
Expand Down Expand Up @@ -55,6 +56,7 @@ export const FormFieldPlugin = (props: ContainerProps) => {
setContextFieldValue={setContextFieldValue}
errors={errors}
warnings={warnings}
viewMode={viewMode}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,5 @@ export type ComponentProps = {|
errors: { [id: string]: Array<string> },
warnings: { [id: string]: Array<string> },
setContextFieldValue: (SetFieldValueProps) => void,
viewMode: boolean,
|}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,16 @@ export const usePluginCallbacks = ({
}, [configuredPluginIds, metadataByPluginId, onUpdateField]);

const setContextFieldValue = useCallback(({ fieldId, value }: SetFieldValueProps) => {
pluginContext[fieldId]?.setDataEntryFieldValue(value);
const contextField = pluginContext[fieldId];

if (!contextField) {
log.error(errorCreator(
PluginErrorMessages.SET_CONTEXT_FIELD_VALUE_MISSING_ID,
)({ fieldId, value }));
return;
}

contextField?.setDataEntryFieldValue(value);
}, [pluginContext]);

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ import typeof { newEventSaveTypes } from './newEventSaveTypes';
const makeMapStateToProps = () => {
const programNameSelector = makeProgramNameSelector();

const mapStateToProps = (state: ReduxState, props: Object) =>
({ recentlyAddedRelationshipId: state.newEventPage.recentlyAddedRelationshipId,
ready: !state.activePage.isDataEntryLoading,
error: !props.formFoundation ?
i18n.t('This is not an event program or the metadata is corrupt. See log for details.') : null,
programName: programNameSelector(state),
orgUnitName: state.organisationUnits[state.currentSelections.orgUnitId] &&
const mapStateToProps = (state: ReduxState, props: Object) => ({
recentlyAddedRelationshipId: state.newEventPage.recentlyAddedRelationshipId,
ready: !state.activePage.isDataEntryLoading,
error: !props.formFoundation ?
i18n.t('This is not an event program or the metadata is corrupt. See log for details.') : null,
programName: programNameSelector(state),
orgUnitName: state.organisationUnits[state.currentSelections.orgUnitId] &&
state.organisationUnits[state.currentSelections.orgUnitId].name,
});
});


// $FlowFixMe[not-an-object] automated comment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useCoreOrgUnit } from '../../../../metadataRetrieval/coreOrgUnit';
import { useLocationQuery } from '../../../../utils/routing';
import { useRulesEngine } from './useRulesEngine';
import type { PlainProps } from './NewEventDataEntryWrapper.types';
import { useMetadataForProgramStage } from '../../common/ProgramStage/useMetadataForProgramStage';

const getStyles = () => ({
flexContainer: {
Expand Down Expand Up @@ -41,13 +42,12 @@ const getStyles = () => ({

const NewEventDataEntryWrapperPlain = ({
classes,
formFoundation,
formHorizontal,
stage,
onFormLayoutDirectionChange,
}: PlainProps) => {
const { id: programId } = useCurrentProgramInfo();
const orgUnitId = useLocationQuery().orgUnitId;
const { formFoundation, stage } = useMetadataForProgramStage({ programId });
const { orgUnit, error } = useCoreOrgUnit(orgUnitId);
const rulesReady = useRulesEngine({ programId, orgUnit, formFoundation });
const titleText = useScopeTitleText(programId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,13 @@ import { NewEventDataEntryWrapperComponent } from './NewEventDataEntryWrapper.co
import {
setNewEventFormLayoutDirection,
} from './newEventDataEntryWrapper.actions';
import {
makeStageSelector,
} from './newEventDataEntryWrapper.selectors';
import { getDataEntryHasChanges } from '../getNewEventDataEntryHasChanges';
import type { Props, ContainerProps, StateProps, MapStateToProps } from './NewEventDataEntryWrapper.types';

const makeMapStateToProps = (): MapStateToProps => {
const stageSelector = makeStageSelector();

return (state: ReduxState): StateProps => {
const stage = stageSelector(state);
const formFoundation = stage && stage.stageForm ? stage.stageForm : null;
return ({
stage,
formFoundation,
dataEntryHasChanges: getDataEntryHasChanges(state),
formHorizontal: (formFoundation && formFoundation.customForm ? false : !!state.newEventPage.formHorizontal),
});
};
};
const makeMapStateToProps = (): MapStateToProps => (state: ReduxState): StateProps => ({
dataEntryHasChanges: getDataEntryHasChanges(state),
formHorizontal: !!state.newEventPage.formHorizontal,
});

const mapDispatchToProps = (dispatch: ReduxDispatch) => ({
onFormLayoutDirectionChange: (formHorizontal: boolean) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// @flow
import type { ProgramStage, RenderFoundation } from '../../../../metaData';

export type PlainProps = {|
...CssClasses,
Expand All @@ -10,18 +9,15 @@ export type Props = {|
dataEntryHasChanges: boolean,
formHorizontal: ?boolean,
onFormLayoutDirectionChange: (formHorizontal: boolean) => void,
formFoundation: ?RenderFoundation,
stage: ?ProgramStage,
|}

export type StateProps = {|
dataEntryHasChanges: boolean,
formHorizontal: ?boolean,
formFoundation: ?RenderFoundation,
stage: ?ProgramStage,
|}

export type ContainerProps = {|

|};

export type MapStateToProps = (ReduxState, ContainerProps) => StateProps;

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const useRulesEngine = ({
}: {
programId: string,
orgUnit: ?OrgUnit,
formFoundation: RenderFoundation,
formFoundation: ?RenderFoundation,
}) => {
const dispatch = useDispatch();
const program = useMemo(() => programId && getEventProgramThrowIfNotFound(programId), [programId]);
Expand All @@ -25,7 +25,7 @@ export const useRulesEngine = ({
// Refactor the helper methods (getCurrentClientValues, getCurrentClientMainData in rules/actionsCreator) to be more explicit with the arguments.
const state = useSelector(stateArg => stateArg);
useEffect(() => {
if (orgUnit && program) {
if (orgUnit && program && !!formFoundation) {
dispatch(batchActions([
getRulesActions({
state,
Expand All @@ -42,6 +42,7 @@ export const useRulesEngine = ({
dispatch,
program,
orgUnit,
formFoundation,
]);

return !!orgUnit && orgUnitRef.current === orgUnit;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// @flow
import type {
CachedDataElement,
CachedOptionSet,
CachedProgramStage,
} from '../../../../storageControllers';
import type { DataEntryFormConfig } from '../TEIAndEnrollment';
import { getUserStorageController, userStores } from '../../../../storageControllers';
import { ProgramStageFactory } from '../../../../metaDataMemoryStoreBuilders/programs/factory/programStage';

export const buildProgramStageMetadata = async ({
cachedProgramStage,
programId,
cachedDataElements,
cachedOptionSets,
locale,
minorServerVersion,
dataEntryFormConfig,
}: {
cachedProgramStage: CachedProgramStage,
programId: string,
cachedOptionSets: Array<CachedOptionSet>,
cachedDataElements: Array<CachedDataElement>,
dataEntryFormConfig: ?DataEntryFormConfig,
locale: string,
minorServerVersion: number,
}) => {
const storageController = getUserStorageController();

const cachedRelationshipTypes = await storageController.getAll(userStores.RELATIONSHIP_TYPES);

const programStageFactory = new ProgramStageFactory({
cachedOptionSets: new Map<string, CachedOptionSet>(cachedOptionSets.map(optionSet => [optionSet.id, optionSet])),
cachedRelationshipTypes,
cachedDataElements: new Map<string, CachedDataElement>(cachedDataElements.map(dataElement => [dataElement.id, dataElement])),
locale,
minorServerVersion,
dataEntryFormConfig,
});

return programStageFactory.build(
cachedProgramStage,
programId,
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// @flow

export { useDataElementsForStage } from './useDataElementsForStage';
export { buildProgramStageMetadata } from './buildProgramStageMetadata';
Loading
Loading