Skip to content

Commit

Permalink
fix: [DHIS2-16084] Filter unidirectional relationship types (#3477)
Browse files Browse the repository at this point in the history
  • Loading branch information
eirikhaugstulen authored Dec 14, 2023
1 parent a934291 commit 3579fc0
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const TrackedEntityRelationshipsWrapper = ({
);
}

if (!relationshipTypes || !addRelationshipRenderElement) {
if (!relationshipTypes?.length || !addRelationshipRenderElement) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { RelationshipsWidget } from '../common/RelationshipsWidget';
import { RelationshipSearchEntities, useRelationships } from '../common/useRelationships';
import { NewTrackedEntityRelationship } from './NewTrackedEntityRelationship';
import { useTrackedEntityTypeName } from './hooks/useTrackedEntityTypeName';
import { useRelationshipTypes } from '../common/RelationshipsWidget/useRelationshipTypes';

export const WidgetTrackedEntityRelationship = ({
relationshipTypes: cachedRelationshipTypes,
Expand All @@ -21,8 +22,17 @@ export const WidgetTrackedEntityRelationship = ({
renderTrackedEntitySearch,
renderTrackedEntityRegistration,
}: WidgetTrackedEntityRelationshipProps) => {
const { data: relationships, isError, isLoading: isLoadingRelationships } = useRelationships(teiId, RelationshipSearchEntities.TRACKED_ENTITY);
const { data: relationshipTypes } = useRelationshipTypes(cachedRelationshipTypes);
const { data: trackedEntityTypeName, isLoading: isLoadingTEType } = useTrackedEntityTypeName(trackedEntityTypeId);
const {
data: relationships,
isError,
isLoading: isLoadingRelationships,
} = useRelationships({
entityId: teiId,
searchMode: RelationshipSearchEntities.TRACKED_ENTITY,
relationshipTypes,
});

const isLoading = useMemo(() => isLoadingRelationships || isLoadingTEType,
[isLoadingRelationships, isLoadingTEType],
Expand All @@ -36,6 +46,10 @@ export const WidgetTrackedEntityRelationship = ({
);
}

if (!relationshipTypes?.length) {
return null;
}

return (
<RelationshipsWidget
title={i18n.t('{{trackedEntityTypeName}} relationships', {
Expand All @@ -44,27 +58,23 @@ export const WidgetTrackedEntityRelationship = ({
})}
isLoading={isLoading}
relationships={relationships}
cachedRelationshipTypes={cachedRelationshipTypes}
relationshipTypes={relationshipTypes}
sourceId={teiId}
onLinkedRecordClick={onLinkedRecordClick}
>
{
relationshipTypes => (
<NewTrackedEntityRelationship
teiId={teiId}
renderElement={addRelationshipRenderElement}
relationshipTypes={relationshipTypes}
trackedEntityTypeId={trackedEntityTypeId}
programId={programId}
orgUnitId={orgUnitId}
onOpenAddRelationship={onOpenAddRelationship}
onCloseAddRelationship={onCloseAddRelationship}
onSelectFindMode={onSelectFindMode}
renderTrackedEntitySearch={renderTrackedEntitySearch}
renderTrackedEntityRegistration={renderTrackedEntityRegistration}
/>
)
}
<NewTrackedEntityRelationship
teiId={teiId}
renderElement={addRelationshipRenderElement}
relationshipTypes={relationshipTypes}
trackedEntityTypeId={trackedEntityTypeId}
programId={programId}
orgUnitId={orgUnitId}
onOpenAddRelationship={onOpenAddRelationship}
onCloseAddRelationship={onCloseAddRelationship}
onSelectFindMode={onSelectFindMode}
renderTrackedEntitySearch={renderTrackedEntitySearch}
renderTrackedEntityRegistration={renderTrackedEntityRegistration}
/>
</RelationshipsWidget>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Chip, IconLink24, spacers } from '@dhis2/ui';
import { withStyles } from '@material-ui/core';
import { Widget } from '../../../Widget';
import { useGroupedLinkedEntities } from './useGroupedLinkedEntities';
import { useRelationshipTypes } from './useRelationshipTypes';
import { LinkedEntitiesViewer } from './LinkedEntitiesViewer.component';
import type { Props, StyledProps } from './relationshipsWidget.types';
import { LoadingMaskElementCenter } from '../../../LoadingMasks';
Expand All @@ -23,14 +22,13 @@ const RelationshipsWidgetPlain = ({
title,
relationships,
isLoading,
cachedRelationshipTypes,
sourceId,
relationshipTypes,
onLinkedRecordClick,
children,
classes,
}: StyledProps) => {
const [open, setOpenStatus] = useState(true);
const { data: relationshipTypes } = useRelationshipTypes(cachedRelationshipTypes);
const groupedLinkedEntities = useGroupedLinkedEntities(sourceId, relationshipTypes, relationships);

if (isLoading) {
Expand Down Expand Up @@ -83,9 +81,8 @@ const RelationshipsWidgetPlain = ({
onLinkedRecordClick={onLinkedRecordClick}
/>
)
}{
relationshipTypes && children(relationshipTypes)
}
{children}
</Widget>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import type { LinkedRecordClick } from './types';
export type Props = $ReadOnly<{|
title: string,
relationships?: Array<InputRelationshipData>,
cachedRelationshipTypes?: RelationshipTypes,
relationshipTypes: RelationshipTypes,
isLoading: boolean,
sourceId: string,
onLinkedRecordClick: LinkedRecordClick,
children: (relationshipTypes: RelationshipTypes) => Node,
children: Node,
|}>;

export type StyledProps = $ReadOnly<{|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { dataElementTypes } from '../../../../metaData';
import { RELATIONSHIP_ENTITIES } from '../constants';
import { convertClientToList, convertServerToClient } from '../../../../converters';
import type { GroupedLinkedEntities, LinkedEntityData } from './types';
import type { InputRelationshipData, RelationshipTypes } from '../Types';
import type { ApiLinkedEntity, InputRelationshipData, RelationshipTypes } from '../Types';


const getFallbackFieldsByRelationshipEntity = {
Expand Down Expand Up @@ -137,18 +137,19 @@ const getLinkedEntityData = (apiLinkedEntity, relationshipCreatedAt, pendingApiR
return null;
};

const determineLinkedEntity = (fromEntity, toEntity, sourceId) => {
if (fromEntity.trackedEntity?.trackedEntity === sourceId || fromEntity.event?.event === sourceId) {
return toEntity;
}
export const determineLinkedEntity =
(fromEntity: ApiLinkedEntity, toEntity: ApiLinkedEntity, sourceId: string): ApiLinkedEntity | null => {
if (fromEntity.trackedEntity?.trackedEntity === sourceId || fromEntity.event?.event === sourceId) {
return toEntity;
}

if (toEntity.trackedEntity?.trackedEntity === sourceId || toEntity.event?.event === sourceId) {
return fromEntity;
}
if (toEntity.trackedEntity?.trackedEntity === sourceId || toEntity.event?.event === sourceId) {
return fromEntity;
}

log.error(errorCreator('Could not determine linked entity')({ fromEntity, toEntity, sourceId }));
return null;
};
log.error(errorCreator('Could not determine linked entity')({ fromEntity, toEntity, sourceId }));
return null;
};

export const useGroupedLinkedEntities = (
sourceId: string,
Expand Down Expand Up @@ -184,6 +185,10 @@ export const useGroupedLinkedEntities = (
return accGroupedLinkedEntities;
}

if (!relationshipType.bidirectional && apiLinkedEntity === fromEntity) {
return accGroupedLinkedEntities;
}

const linkedEntityData = getLinkedEntityData(apiLinkedEntity, relationshipCreatedAt, pendingApiResponse);
if (!linkedEntityData) {
return accGroupedLinkedEntities;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
// @flow
import { useMemo } from 'react';
import { useApiDataQuery } from '../../../../utils/reactQueryHelpers';
import type { InputRelationshipData } from '../Types';
import type { InputRelationshipData, RelationshipTypes } from '../Types';
import { determineLinkedEntity } from '../RelationshipsWidget/useGroupedLinkedEntities';

export const RelationshipSearchEntities = Object.freeze({
TRACKED_ENTITY: 'trackedEntity',
ENROLLMENT: 'enrollment',
EVENT: 'event',
});

type Props = {|
entityId: string,
searchMode: $Values<typeof RelationshipSearchEntities>,
relationshipTypes: ?RelationshipTypes,
|}

type ReturnData = Array<InputRelationshipData>;

export const useRelationships = (entityId: string, searchMode: string) => {
export const useRelationships = ({ entityId, searchMode, relationshipTypes }: Props) => {
const query = useMemo(() => ({
resource: 'tracker/relationships',
params: {
// $FlowFixMe - searchMode should be a valid key of RelationshipSearchEntities
[searchMode]: entityId,
fields: 'relationshipType,createdAt,from[trackedEntity[trackedEntity,attributes,program,orgUnit,trackedEntityType],event[event,dataValues,program,orgUnit,orgUnitName,status,createdAt]],to[trackedEntity[trackedEntity,attributes,program,orgUnit,trackedEntityType],event[event,dataValues,program,orgUnit,orgUnitName,status,createdAt]]',
},
Expand All @@ -25,7 +33,32 @@ export const useRelationships = (entityId: string, searchMode: string) => {
query,
{
enabled: !!entityId,
select: ({ instances }: any) => instances,
select: ({ instances }: any) => {
if (!relationshipTypes?.length || !instances?.length) {
return [];
}

return instances.reduce((acc, relationship) => {
const relationshipType = relationshipTypes
.find(relType => relType.id === relationship.relationshipType);
if (!relationshipType) {
return acc;
}
const { from, to } = relationship;
const apiLinkedEntity = determineLinkedEntity(from, to, entityId);

if (!apiLinkedEntity) {
return acc;
}

if (!relationshipType.bidirectional && apiLinkedEntity === from) {
return acc;
}

acc.push(relationship);
return acc;
}, []);
},
},
);
};

0 comments on commit 3579fc0

Please sign in to comment.