Skip to content

Commit

Permalink
feat: add inheritable TEAs
Browse files Browse the repository at this point in the history
  • Loading branch information
eirikhaugstulen committed Nov 16, 2023
1 parent 29e9c70 commit 5390281
Show file tree
Hide file tree
Showing 15 changed files with 104 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type StaticPatternValues = {

const useClientAttributesWithSubvalues = (program: InputProgramData, attributes: Array<InputAttribute>) => {
const dataEngine = useDataEngine();
const [listAttributes, setListAttributes] = useState([]);
const [listAttributes, setListAttributes] = useState(null);

const getListAttributes = useCallback(async () => {
if (program && attributes) {
Expand Down Expand Up @@ -139,8 +139,6 @@ export const useFormValues = ({ program, trackedEntityInstanceAttributes, orgUni
const formValuesReadyRef = useRef<any>(false);
const [formValues, setFormValues] = useState<any>({});
const [clientValues, setClientValues] = useState<any>({});
const areAttributesWithSubvaluesReady =
(teiId && clientAttributesWithSubvalues.length > 0) || (!teiId && clientAttributesWithSubvalues.length === 0);

useEffect(() => {
formValuesReadyRef.current = false;
Expand All @@ -152,7 +150,7 @@ export const useFormValues = ({ program, trackedEntityInstanceAttributes, orgUni
formFoundation &&
Object.entries(formFoundation).length > 0 &&
formValuesReadyRef.current === false &&
areAttributesWithSubvaluesReady
!!clientAttributesWithSubvalues
) {
const staticPatternValues = { orgUnitCode: orgUnit.code };
const querySingleResource = makeQuerySingleResource(dataEngine.query.bind(dataEngine));
Expand All @@ -172,7 +170,6 @@ export const useFormValues = ({ program, trackedEntityInstanceAttributes, orgUni
clientAttributesWithSubvalues,
formValuesReadyRef,
orgUnit,
areAttributesWithSubvaluesReady,
searchTerms,
dataEngine,
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const getStyles = () => ({

type OrgUnitValue = {
id: string,
name: string,
displayName: string,
path: string,
}

Expand Down Expand Up @@ -44,15 +44,15 @@ class SingleOrgUnitSelectFieldPlain extends React.Component<Props, State> {
const { classes } = this.props;
return (
<div className={classes.selectedOrgUnitContainer}>
<Chip onRemove={this.onDeselectOrgUnit}>{selectedOrgUnit.name}</Chip>
<Chip onRemove={this.onDeselectOrgUnit}>{selectedOrgUnit.displayName}</Chip>
</div>
);
}

onSelectOrgUnit = (orgUnit: Object) => {
this.props.onBlur({
id: orgUnit.id,
name: orgUnit.displayName,
displayName: orgUnit.displayName,
path: orgUnit.path,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const NewEnrollmentRelationshipPlain =
theme,
onSave,
programId,
originTeiId,
inheritedAttributes,
orgUnitId,
duplicatesReviewPageSize,
renderDuplicatesDialogActions,
Expand All @@ -35,6 +37,8 @@ const NewEnrollmentRelationshipPlain =
renderDuplicatesDialogActions={renderDuplicatesDialogActions}
renderDuplicatesCardActions={renderDuplicatesCardActions}
ExistingUniqueValueDialogActions={ExistingUniqueValueDialogActions}
teiId={originTeiId}
trackedEntityInstanceAttributes={inheritedAttributes}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import type {
SaveForEnrollmentAndTeiRegistration,
ExistingUniqueValueDialogActionsComponent,
} from '../../../../../../DataEntries';
import type { InputAttribute } from '../../../../../../DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues';

export type Props = {|
theme: Theme,
programId: string,
orgUnitId: string,
originTeiId: ?string,
inheritedAttributes: Array<InputAttribute>,
enrollmentMetadata?: Enrollment,
onSave: SaveForEnrollmentAndTeiRegistration,
duplicatesReviewPageSize: number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ type Props = {

export class RegisterTeiDataEntryComponent extends React.Component<Props> {
render() {
const { showDataEntry, programId, onSaveWithoutEnrollment, onSaveWithEnrollment, ...passOnProps } = this.props;
const {
showDataEntry,
programId,
onSaveWithoutEnrollment,
onSaveWithEnrollment,
...passOnProps
} = this.props;

if (!showDataEntry) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,14 @@ const DialogButtons = ({ onCancel, onSave, trackedEntityName }) => (
const RegisterTeiPlain = ({
dataEntryId,
onLink,
originTeiId,
onSaveWithoutEnrollment,
onSaveWithEnrollment,
onGetUnsavedAttributeValues,
trackedEntityName,
trackedEntityTypeId,
selectedScopeId,
inheritedAttributes,
classes,
}: ComponentProps) => {
const { resultsPageSize } = useContext(ResultsPageSizeContext);
Expand Down Expand Up @@ -110,6 +112,8 @@ const RegisterTeiPlain = ({
renderDuplicatesDialogActions={renderDuplicatesDialogActions}
renderDuplicatesCardActions={renderDuplicatesCardActions}
ExistingUniqueValueDialogActions={ExistingUniqueValueDialogActions}
originTeiId={originTeiId}
inheritedAttributes={inheritedAttributes}
/>
</div>
<DataEntryWidgetOutput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,31 @@ import { useSelector } from 'react-redux';
import { RegisterTeiComponent } from './RegisterTei.component';
import type { ContainerProps } from './RegisterTei.types';
import { useScopeInfo } from '../../../../../hooks';
import { useInheritedAttributeValues } from '../useInheritedAttributeValues';

export const RegisterTei = ({
onLink,
onSave,
onGetUnsavedAttributeValues,
teiId,
trackedEntityTypeId,
suggestedProgramId,
}: ContainerProps) => {
const dataEntryId = 'relationship';
const error = useSelector(({ newRelationshipRegisterTei }) => (newRelationshipRegisterTei.error));
const selectedScopeId = suggestedProgramId || trackedEntityTypeId;
const { trackedEntityName } = useScopeInfo(selectedScopeId);
const {
inheritedAttributes,
originTeiId,
isLoading: isLoadingAttributes } = useInheritedAttributeValues({
teiId,
trackedEntityTypeId,
});

if (isLoadingAttributes) {
return null;
}

return (
<RegisterTeiComponent
Expand All @@ -28,6 +41,8 @@ export const RegisterTei = ({
selectedScopeId={selectedScopeId}
error={error}
trackedEntityTypeId={trackedEntityTypeId}
originTeiId={originTeiId}
inheritedAttributes={inheritedAttributes}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// @flow
import type { InputAttribute } from '../../../../DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues';

export type SharedProps = {|
onLink: (teiId: string, values: Object) => void,
onGetUnsavedAttributeValues?: ?Function,
Expand All @@ -7,6 +9,7 @@ export type SharedProps = {|

export type ContainerProps = {|
suggestedProgramId: string,
teiId: string,
onSave: (teiPayload: Object) => void,
...SharedProps,
|};
Expand All @@ -16,6 +19,8 @@ export type ComponentProps = {|
error: string,
dataEntryId: string,
trackedEntityName: ?string,
originTeiId: ?string,
inheritedAttributes: Array<InputAttribute>,
onSaveWithEnrollment: () => void,
onSaveWithoutEnrollment: () => void,
...SharedProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export const TrackedEntityRelationshipsWrapper = ({
suggestedProgramId={suggestedProgramId}
onLink={onLinkToTrackedEntityFromSearch}
onSave={onLinkToTrackedEntityFromRegistration}
teiId={teiId}
onGetUnsavedAttributeValues={() => console.log('get unsaved')}
trackedEntityTypeId={selectedTrackedEntityTypeId}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// @flow
import type { InputAttribute } from '../../../DataEntries/EnrollmentRegistrationEntry/hooks/useFormValues';
import { useApiDataQuery } from '../../../../utils/reactQueryHelpers';
import { getTrackedEntityTypeThrowIfNotFound } from '../../../../metaData';

type Props = {
teiId: string,
trackedEntityTypeId: string,
};

type Return = {
inheritedAttributes: Array<InputAttribute>,
originTeiId: ?string,
isLoading: boolean,
};
export const useInheritedAttributeValues = ({ teiId, trackedEntityTypeId }: Props): Return => {
const trackedEntityType = getTrackedEntityTypeThrowIfNotFound(trackedEntityTypeId);
const inheritedAttributeIds = trackedEntityType.attributes.reduce((acc, attribute) => {
if (attribute.inherit) {
acc.push(attribute.id);
}
return acc;
}, []);

const { data, isLoading } = useApiDataQuery(
['inheritedAttributeValues', teiId],
{
resource: 'tracker/trackedEntities',
id: teiId,
params: {
fields: ['attributes'],
},
}, {
enabled: !!teiId,
select: (response) => {
const attributes = response.attributes || [];
return attributes
.filter(attribute => inheritedAttributeIds.includes(attribute.attribute));
},
});

return {
inheritedAttributes: data ?? [],
originTeiId: null,
isLoading,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class DataElement {
_displayInReports: boolean;
_icon: Icon | void;
_unique: ?Unique;
_inherit: boolean;
_searchable: ?boolean;
_url: ?string;
_attributeValues: Array<CachedAttributeValue>
Expand Down Expand Up @@ -157,6 +158,14 @@ export class DataElement {
return this._unique;
}

get inherit(): boolean {
return this._inherit;
}

set inherit(value: boolean) {
this._inherit = value;
}

set searchable(searchable: boolean) {
this._searchable = searchable;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export class DataElementFactory {
dataElement.compulsory = cachedProgramTrackedEntityAttribute.mandatory;
dataElement.code = cachedTrackedEntityAttribute.code;
dataElement.attributeValues = cachedTrackedEntityAttribute.attributeValues;
dataElement.inherit = cachedTrackedEntityAttribute.inherit;
dataElement.name =
this._getAttributeTranslation(
cachedTrackedEntityAttribute.translations,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export class DataElementFactory {
cachedAttribute.translations, DataElementFactory.translationPropertyNames.DESCRIPTION) ||
cachedAttribute.description;
o.displayInForms = true;
o.inherit = cachedAttribute.inherit;
o.displayInReports = cachedTrackedEntityTypeAttribute.displayInList;
o.disabled = false;
o.type = cachedAttribute.valueType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const storeTrackedEntityAttributes = (ids: Array<string>) => {
resource: 'trackedEntityAttributes',
params: {
fields: 'id,displayName,displayShortName,displayFormName,description,valueType,optionSetValue,unique,orgunitScope,' +
'pattern,code,attributeValues,translations[property,locale,value],optionSet[id]',
'pattern,code,attributeValues,inherit,translations[property,locale,value],optionSet[id]',
filter: `id:in:[${ids.join(',')}]`,
pageSize: ids.length,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export type CachedTrackedEntityAttribute = {
translations: Array<CachedAttributeTranslation>,
valueType: string,
optionSetValue: boolean,
inherit: boolean,
optionSet: { id: string },
unique: ?boolean,
orgunitScope: ?boolean,
Expand Down

0 comments on commit 5390281

Please sign in to comment.