From 32381830869d81ce0a3306ce409ed895d48b055d Mon Sep 17 00:00:00 2001 From: Simona Domnisoru Date: Fri, 26 Jan 2024 13:32:31 +0100 Subject: [PATCH 1/4] feat: handle different response shape --- .../featuresSupport/support.js | 4 +++- .../hooks/useEventsInOrgUnit.js | 4 +++- .../DataEntry/FormFoundation/DataElement.js | 4 +++- .../useRelationships/useRelationships.js | 8 ++++--- .../epics/getEventListData.js | 2 +- .../getEventListData/getEventListData.js | 9 +++++--- .../helpers/getTeiListData/getTeiListData.js | 6 +++-- .../capture-core/events/eventRequests.js | 8 ++++--- .../factory/enrollment/DataElementFactory.js | 4 +++- .../TrackedEntityType/DataElementFactory.js | 7 +++--- .../relationships/relationshipRequests.js | 8 ++++--- .../trackedEntityInstanceRequests.js | 8 ++++--- .../utils/api/handleAPIResponse.js | 22 +++++++++++++++++++ .../capture-core/utils/api/index.js | 1 + 14 files changed, 70 insertions(+), 25 deletions(-) create mode 100644 src/core_modules/capture-core/utils/api/handleAPIResponse.js diff --git a/src/core_modules/capture-core-utils/featuresSupport/support.js b/src/core_modules/capture-core-utils/featuresSupport/support.js index 207c929c21..d410b1cacf 100644 --- a/src/core_modules/capture-core-utils/featuresSupport/support.js +++ b/src/core_modules/capture-core-utils/featuresSupport/support.js @@ -3,6 +3,7 @@ export const FEATURES = Object.freeze({ programStageWorkingList: 'programStageWorkingList', storeProgramStageWorkingList: 'storeProgramStageWorkingList', customIcons: 'customIcons', + exportablePayload: 'exportablePayload', }); // The first minor version that supports the feature @@ -10,7 +11,8 @@ const MINOR_VERSION_SUPPORT = Object.freeze({ [FEATURES.programStageWorkingList]: 39, [FEATURES.storeProgramStageWorkingList]: 40, [FEATURES.customIcons]: 41, + [FEATURES.exportablePayload]: 41, }); -export const hasAPISupportForFeature = (minorVersion: string, featureName: string) => +export const hasAPISupportForFeature = (minorVersion: string | number, featureName: string) => MINOR_VERSION_SUPPORT[featureName] <= Number(minorVersion) || false; diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/hooks/useEventsInOrgUnit.js b/src/core_modules/capture-core/components/WidgetEventSchedule/hooks/useEventsInOrgUnit.js index f51b8d2ec8..15b3b09c01 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/hooks/useEventsInOrgUnit.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/hooks/useEventsInOrgUnit.js @@ -1,5 +1,6 @@ // @flow import { useMemo, useEffect } from 'react'; +import { handleAPIResponse } from 'capture-core/utils/api'; import { useDataQuery } from '@dhis2/app-runtime'; export const useEventsInOrgUnit = (orgUnitId: string, selectedDate: string) => { @@ -31,5 +32,6 @@ export const useEventsInOrgUnit = (orgUnitId: string, selectedDate: string) => { } }, [refetch, orgUnitId, selectedDate]); - return { error, events: !loading && data ? data.events.instances : [] }; + const apiEvents = handleAPIResponse('events', data?.events); + return { error, events: !loading && data ? apiEvents : [] }; }; diff --git a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js index c8e09b913c..a94775628e 100644 --- a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js +++ b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js @@ -1,6 +1,7 @@ // @flow /* eslint-disable no-underscore-dangle */ import log from 'loglevel'; +import { handleAPIResponse } from 'capture-core/utils/api'; import i18n from '@dhis2/d2-i18n'; import { pipe, errorCreator } from 'capture-core-utils'; @@ -81,7 +82,8 @@ const buildDataElementUnique = ( }); } return requestPromise.then((result) => { - const otherTrackedEntityInstances = result?.instances?.filter(item => item.trackedEntity !== contextProps.trackedEntityInstanceId) || []; + const apiTrackedEntities = handleAPIResponse('trackedEntities', result); + const otherTrackedEntityInstances = apiTrackedEntities.filter(item => item.trackedEntity !== contextProps.trackedEntityInstanceId); const trackedEntityInstance = (otherTrackedEntityInstances && otherTrackedEntityInstances[0]) || {}; const data = { diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js b/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js index 7f626a84c1..9634a0a944 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js @@ -1,5 +1,6 @@ // @flow import { useMemo } from 'react'; +import { handleAPIResponse } from 'capture-core/utils/api'; import { useApiDataQuery } from '../../../../utils/reactQueryHelpers'; import type { InputRelationshipData, RelationshipTypes } from '../Types'; import { determineLinkedEntity } from '../RelationshipsWidget/useGroupedLinkedEntities'; @@ -33,12 +34,13 @@ export const useRelationships = ({ entityId, searchMode, relationshipTypes }: Pr query, { enabled: !!entityId, - select: ({ instances }: any) => { - if (!relationshipTypes?.length || !instances?.length) { + select: (apiResponse: any) => { + const apiRelationships = handleAPIResponse('relationships', apiResponse); + if (!relationshipTypes?.length || !apiRelationships?.length) { return []; } - return instances.reduce((acc, relationship) => { + return apiRelationships.reduce((acc, relationship) => { const relationshipType = relationshipTypes .find(relType => relType.id === relationship.relationshipType); if (!relationshipType) { diff --git a/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/epics/getEventListData.js b/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/epics/getEventListData.js index d3ac4f35ed..7884ce257b 100644 --- a/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/epics/getEventListData.js +++ b/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/epics/getEventListData.js @@ -182,7 +182,7 @@ export const getEventListData = async ({ querySingleResource: QuerySingleResource, }) => { const mainColumns = getMainColumns(columnsMetaForDataFetching); - + // $FlowFixMe const { eventContainers, pagingData, request } = await getEvents( createApiQueryArgs(queryArgs, mainColumns, categoryCombinationId), absoluteApiPath, diff --git a/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getEventListData/getEventListData.js b/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getEventListData/getEventListData.js index c593ff8f1f..43c52fa5e2 100644 --- a/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getEventListData/getEventListData.js +++ b/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getEventListData/getEventListData.js @@ -1,4 +1,5 @@ // @flow +import { handleAPIResponse } from 'capture-core/utils/api'; import { convertToClientEvents } from './convertToClientEvents'; import { getSubvalues, @@ -63,10 +64,11 @@ export const getEventListData = async ( resource: 'tracker/events', queryArgs: createApiEventQueryArgs(rawQueryArgs, columnsMetaForDataFetching, filtersOnlyMetaForDataFetching), }; - const { instances: apiEvents = [] } = await querySingleResource({ + const apiEventsResponse = await querySingleResource({ resource: resourceEvents, params: queryArgsEvents, }); + const apiEvents = handleAPIResponse('events', apiEventsResponse); const trackedEntityIds = apiEvents .reduce((acc, { trackedEntity }) => (acc.includes(trackedEntity) ? acc : [...acc, trackedEntity]), []) @@ -76,13 +78,14 @@ export const getEventListData = async ( resource: 'tracker/trackedEntities', queryArgs: createApiTEIsQueryArgs(rawQueryArgs, trackedEntityIds), }; - const { instances: apiTeis = [] } = await querySingleResource({ + const apiTEIResponse = await querySingleResource({ resource: resourceTEIs, params: queryArgsTEIs, }); + const apiTrackedEntities = handleAPIResponse('trackedEntities', apiTEIResponse); const columnsMetaForDataFetchingArray = getColumnsQueryArgs(columnsMetaForDataFetching); - const clientEvents = convertToClientEvents(addTEIsData(apiEvents, apiTeis), columnsMetaForDataFetchingArray); + const clientEvents = convertToClientEvents(addTEIsData(apiEvents, apiTrackedEntities), columnsMetaForDataFetchingArray); const clientWithSubvalues = await getSubvalues(querySingleResource, absoluteApiPath)( clientEvents, columnsMetaForDataFetchingArray, diff --git a/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getTeiListData/getTeiListData.js b/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getTeiListData/getTeiListData.js index 4abdad5b1b..7829289f32 100644 --- a/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getTeiListData/getTeiListData.js +++ b/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getTeiListData/getTeiListData.js @@ -1,4 +1,5 @@ // @flow +import { handleAPIResponse } from 'capture-core/utils/api'; import { convertToClientTeis } from './convertToClientTeis'; import { getSubvalues, getApiFilterQueryArgs, getMainApiFilterQueryArgs } from '../getListDataCommon'; import type { RawQueryArgs } from './types'; @@ -41,12 +42,13 @@ export const getTeiListData = async ( queryArgs: createApiQueryArgs(rawQueryArgs, columnsMetaForDataFetching, filtersOnlyMetaForDataFetching), }; - const { instances: apiTeis = [] } = await querySingleResource({ + const apiResponse = await querySingleResource({ resource, params: queryArgs, }); + const apiTrackedEntities = handleAPIResponse('trackedEntities', apiResponse); const columnsMetaForDataFetchingArray = [...columnsMetaForDataFetching.values()]; - const clientTeis = convertToClientTeis(apiTeis, columnsMetaForDataFetchingArray, rawQueryArgs.programId); + const clientTeis = convertToClientTeis(apiTrackedEntities, columnsMetaForDataFetchingArray, rawQueryArgs.programId); const clientTeisWithSubvalues = await getSubvalues(querySingleResource, absoluteApiPath)(clientTeis, columnsMetaForDataFetchingArray); return { diff --git a/src/core_modules/capture-core/events/eventRequests.js b/src/core_modules/capture-core/events/eventRequests.js index e598b93a16..4e400072ca 100644 --- a/src/core_modules/capture-core/events/eventRequests.js +++ b/src/core_modules/capture-core/events/eventRequests.js @@ -1,5 +1,6 @@ // @flow import log from 'loglevel'; +import { handleAPIResponse } from 'capture-core/utils/api'; import { errorCreator } from 'capture-core-utils'; import { programCollection } from '../metaDataMemoryStores/programCollection/programCollection'; import { convertValue } from '../converters/serverToClient'; @@ -175,19 +176,20 @@ export async function getEvents( url: 'tracker/events', queryParams, }; - const apiRes = await querySingleResource({ + const apiResponse = await querySingleResource({ resource: 'tracker/events', params: queryParams, }); - const eventContainers = apiRes && apiRes.instances ? await apiRes.instances.reduce(async (accEventsPromise, apiEvent) => { + const apiEvents = handleAPIResponse('events', apiResponse); + const eventContainers = await apiEvents.reduce(async (accEventsPromise, apiEvent) => { const accEvents = await accEventsPromise; const eventContainer = await convertToClientEvent(apiEvent, absoluteApiPath, querySingleResource); if (eventContainer) { accEvents.push(eventContainer); } return accEvents; - }, Promise.resolve([])) : []; + }, Promise.resolve([])); const pagingData = { rowsPerPage: queryParams.pageSize, diff --git a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js index 27d1222735..09e8d29c0c 100644 --- a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js +++ b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js @@ -1,6 +1,7 @@ // @flow /* eslint-disable no-underscore-dangle */ import log from 'loglevel'; +import { handleAPIResponse } from 'capture-core/utils/api'; import i18n from '@dhis2/d2-i18n'; import { pipe, errorCreator } from 'capture-core-utils'; @@ -106,7 +107,8 @@ export class DataElementFactory { } return requestPromise .then((result) => { - const otherTrackedEntityInstances = result?.instances?.filter(item => item.trackedEntity !== contextProps.trackedEntityInstanceId) || []; + const apiTrackedEntities = handleAPIResponse('trackedEntities', result); + const otherTrackedEntityInstances = apiTrackedEntities.filter(item => item.trackedEntity !== contextProps.trackedEntityInstanceId); const trackedEntityInstance = (otherTrackedEntityInstances && otherTrackedEntityInstances[0]) || {}; const data = { diff --git a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js index 723d148d3c..0ffecd6da5 100644 --- a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js +++ b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js @@ -1,6 +1,7 @@ // @flow /* eslint-disable no-underscore-dangle */ import log from 'loglevel'; +import { handleAPIResponse } from 'capture-core/utils/api'; import i18n from '@dhis2/d2-i18n'; import { pipe, errorCreator } from 'capture-core-utils'; import type { @@ -168,15 +169,15 @@ export class DataElementFactory { } return requestPromise .then((result) => { - const trackedEntityInstance = - (result.instances && result.instances[0]) || {}; + const apiTrackedEntities = handleAPIResponse('trackedEntities', result); + const trackedEntityInstance = apiTrackedEntities[0] || {}; const data = { id: trackedEntityInstance.trackedEntity, tetId: trackedEntityInstance.trackedEntityType, }; return { - valid: result.instances.length === 0, + valid: apiTrackedEntities.length === 0, data, }; }); diff --git a/src/core_modules/capture-core/relationships/relationshipRequests.js b/src/core_modules/capture-core/relationships/relationshipRequests.js index a9b21ec73d..774f0ec487 100644 --- a/src/core_modules/capture-core/relationships/relationshipRequests.js +++ b/src/core_modules/capture-core/relationships/relationshipRequests.js @@ -1,5 +1,5 @@ // @flow -import isArray from 'd2-utilizr/lib/isArray'; +import { handleAPIResponse } from 'capture-core/utils/api'; import { getProgramThrowIfNotFound, EventProgram } from '../metaData'; import type { RelationshipType } from '../metaData'; import type { QuerySingleResource } from '../utils/api/api.types'; @@ -11,11 +11,13 @@ async function getRelationships( relationshipTypes: Array, querySingleResource: QuerySingleResource, ) { - const apiRes = await querySingleResource({ + const apiResponse = await querySingleResource({ resource: 'tracker/relationships', params: queryParams, }); - return apiRes?.instances && isArray(apiRes.instances) ? apiRes.instances?.map(rel => convertServerRelationshipToClient(rel, relationshipTypes)) : null; + const apiRelationships = handleAPIResponse('relationships', apiResponse); + // $FlowFixMe + return apiRelationships.map(rel => convertServerRelationshipToClient(rel, relationshipTypes)); } export function getRelationshipsForEvent( diff --git a/src/core_modules/capture-core/trackedEntityInstances/trackedEntityInstanceRequests.js b/src/core_modules/capture-core/trackedEntityInstances/trackedEntityInstanceRequests.js index b217ff4953..6c5b634419 100644 --- a/src/core_modules/capture-core/trackedEntityInstances/trackedEntityInstanceRequests.js +++ b/src/core_modules/capture-core/trackedEntityInstances/trackedEntityInstanceRequests.js @@ -1,4 +1,5 @@ // @flow +import { handleAPIResponse } from 'capture-core/utils/api'; import { type DataElement, convertDataElementsValues } from '../metaData'; import { convertValue } from '../converters/serverToClient'; import { getSubValues } from './getSubValues'; @@ -63,19 +64,20 @@ export async function getTrackedEntityInstances( absoluteApiPath: string, querySingleResource: QuerySingleResource, ): TrackedEntityInstancesPromise { - const apiRes = await querySingleResource({ + const apiResponse = await querySingleResource({ resource: 'tracker/trackedEntities', params: queryParams, }); + const apiTrackedEntities = handleAPIResponse('trackedEntities', apiResponse); - const trackedEntityInstanceContainers = apiRes && apiRes.instances ? await apiRes.instances.reduce(async (accTeiPromise, apiTei) => { + const trackedEntityInstanceContainers = await apiTrackedEntities.reduce(async (accTeiPromise, apiTei) => { const accTeis = await accTeiPromise; const teiContainer = await convertToClientTei(apiTei, attributes, absoluteApiPath, querySingleResource); if (teiContainer) { accTeis.push(teiContainer); } return accTeis; - }, Promise.resolve([])) : null; + }, Promise.resolve([])); const pagingData = { rowsPerPage: queryParams.pageSize, diff --git a/src/core_modules/capture-core/utils/api/handleAPIResponse.js b/src/core_modules/capture-core/utils/api/handleAPIResponse.js new file mode 100644 index 0000000000..afc29763e0 --- /dev/null +++ b/src/core_modules/capture-core/utils/api/handleAPIResponse.js @@ -0,0 +1,22 @@ +// @flow +import { FEATURES, hasAPISupportForFeature } from 'capture-core-utils'; + +export const handleAPIResponseByMinorVersion = ( + resourceName: string, + apiResponse: any, + minorVersion: string | number, +) => { + if (!apiResponse) { + return []; + } + return hasAPISupportForFeature(minorVersion, FEATURES.exportablePayload) + ? apiResponse[resourceName] || [] + : apiResponse.instances; +}; + +export const handleAPIResponse = (resourceName: string, apiResponse: any) => { + if (!apiResponse) { + return []; + } + return apiResponse[resourceName] || apiResponse.instances || []; +}; diff --git a/src/core_modules/capture-core/utils/api/index.js b/src/core_modules/capture-core/utils/api/index.js index fe6a62041c..1cdfaed41d 100644 --- a/src/core_modules/capture-core/utils/api/index.js +++ b/src/core_modules/capture-core/utils/api/index.js @@ -1,3 +1,4 @@ // @flow export { makeQuerySingleResource } from './makeQuerySingleResource'; +export { handleAPIResponse } from './handleAPIResponse'; export type * from './api.types'; From 471ea8e19cab5b9c9b1b9a7eaeca8010531cafef Mon Sep 17 00:00:00 2001 From: Simona Domnisoru Date: Mon, 29 Jan 2024 11:50:40 +0100 Subject: [PATCH 2/4] test: adapt cypress tests --- .../EnrollmentPage/BreakingTheGlass/index.js | 14 ++++++----- .../EventWorkingListsDev/index.js | 24 ++++++++++--------- .../TeiWorkingListsDev/index.js | 24 ++++++++++--------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/cypress/e2e/EnrollmentPage/BreakingTheGlass/index.js b/cypress/e2e/EnrollmentPage/BreakingTheGlass/index.js index 120dc0a0dc..6a5363f0e2 100644 --- a/cypress/e2e/EnrollmentPage/BreakingTheGlass/index.js +++ b/cypress/e2e/EnrollmentPage/BreakingTheGlass/index.js @@ -4,12 +4,14 @@ import '../sharedSteps'; Given('the tei created by this test is cleared from the database', () => { cy.buildApiUrl('tracker', 'trackedEntities?filter=w75KJ2mc4zz:like:Breaking&filter=zDhUuAYrxNC:like:TheGlass&trackedEntityType=nEenWmSyUEp&page=1&pageSize=5&ouMode=ACCESSIBLE') .then(url => cy.request(url)) - .then(({ body }) => - body.instances.forEach(({ trackedEntity }) => - cy.buildApiUrl('trackedEntityInstances', trackedEntity) - .then(trackedEntityUrl => - cy.request('DELETE', trackedEntityUrl)), - )); + .then(({ body }) => { + const apiTrackedEntities = body.trackedEntities || body.instances || []; + return apiTrackedEntities.forEach(({ trackedEntity }) => + cy + .buildApiUrl('trackedEntityInstances', trackedEntity) + .then(trackedEntityUrl => cy.request('DELETE', trackedEntityUrl)), + ); + }); }); And('you opt temporarily in on new enrollment dashboard in Child programme and WHO RMNCH Tracker', () => { diff --git a/cypress/e2e/WorkingLists/EventWorkingLists/EventWorkingListsDev/index.js b/cypress/e2e/WorkingLists/EventWorkingLists/EventWorkingListsDev/index.js index e1d79d283a..0b507921ea 100644 --- a/cypress/e2e/WorkingLists/EventWorkingLists/EventWorkingListsDev/index.js +++ b/cypress/e2e/WorkingLists/EventWorkingLists/EventWorkingListsDev/index.js @@ -36,25 +36,27 @@ Then('events should be retrieved from the api using the default query args', () .its('response.url') .should('include', 'page=1'); - cy.get('@result').its('response.body.instances').as('events'); + cy.get('@result').its('response.body').as('events'); }); Then('the list should display the events retrieved from the api', () => { cy.get('@events') - .then((events) => { + .then((body) => { + const apiEvents = body.events || body.instances || []; cy.get('[data-test="event-working-lists"]') .find('tr') - .should('have.length', events.length + 1); + .should('have.length', apiEvents.length + 1); }); cy.get('@events') - .then((teis) => { + .then((body) => { + const apiEvents = body.events || body.instances || []; cy.get('[data-test="event-working-lists"]') .find('tr') .each(($teiRow, index) => { const rowId = $teiRow.get(0).getAttribute('data-test'); if (index > 1) { - expect(rowId).to.equal(teis[index - 1].event); + expect(rowId).to.equal(apiEvents[index - 1].event); } }); }); @@ -87,7 +89,7 @@ Then('events assigned to anyone should be retrieved from the api', () => { .its('response.url') .should('include', 'page=1'); - cy.get('@result').its('response.body.instances').as('events'); + cy.get('@result').its('response.body').as('events'); }); When('you apply the assignee filter', () => { @@ -123,7 +125,7 @@ Then('active events that are assigned to anyone should be retrieved from the api .its('response.url') .should('include', 'page=1'); - cy.get('@result').its('response.body.instances').as('events'); + cy.get('@result').its('response.body').as('events'); }); When('you apply the current filter on the event working list', () => { @@ -152,7 +154,7 @@ Then('events where age is between 10 and 20 should be retrieved from the api', ( .its('response.url') .should('include', 'page=1'); - cy.get('@result').its('response.body.instances').as('events'); + cy.get('@result').its('response.body').as('events'); }); When('you click the next page button on the event working list', () => { @@ -172,7 +174,7 @@ Then('new events should be retrieved from the api', () => { .its('response.statusCode') .should('equal', 200); - cy.get('@result').its('response.body.instances').as('events'); + cy.get('@result').its('response.body').as('events'); }); When('you click the previous page button on the event working list', () => { @@ -216,7 +218,7 @@ Then('an event batch capped at 50 records should be retrieved from the api', () .its('response.url') .should('include', 'page=1'); - cy.get('@result').its('response.body.instances').as('events'); + cy.get('@result').its('response.body').as('events'); }); When('you click the report date column header', () => { @@ -248,5 +250,5 @@ Then('events should be retrieved from the api ordered ascendingly by report date .its('response.url') .should('include', 'page=1'); - cy.get('@resultAsc').its('response.body.instances').as('events'); + cy.get('@resultAsc').its('response.body').as('events'); }); diff --git a/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsDev/index.js b/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsDev/index.js index 56989dd920..5a0dd69651 100644 --- a/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsDev/index.js +++ b/cypress/e2e/WorkingLists/TeiWorkingLists/TeiWorkingListsDev/index.js @@ -42,7 +42,7 @@ Then('teis should be retrieved from the api using the default query args', () => .its('response.url') .should('include', 'page=1'); - cy.get('@result').its('response.body.instances').as('teis'); + cy.get('@result').its('response.body').as('teis'); }); Then('the first page of the default tei working list should be displayed', () => { @@ -89,7 +89,7 @@ Then('teis with an active enrollment should be retrieved from the api', () => { .its('response.url') .should('include', 'page=1'); - cy.get('@result').its('response.body.instances').as('teis'); + cy.get('@result').its('response.body').as('teis'); }); When('you apply the assignee filter', () => { @@ -118,7 +118,7 @@ Then('teis with active enrollments and unassigned events should be retrieved fro .its('response.url') .should('include', 'page=1'); - cy.get('@result').its('response.body.instances').as('teis'); + cy.get('@result').its('response.body').as('teis'); }); When('you apply the current filter on the tei working list', () => { @@ -143,25 +143,27 @@ Then('teis with a first name containing John should be retrieved from the api', .its('response.url') .should('include', 'page=1'); - cy.get('@result').its('response.body.instances').as('teis'); + cy.get('@result').its('response.body').as('teis'); }); Then('the list should display the teis retrieved from the api', () => { cy.get('@teis') - .then((teis) => { + .then((body) => { + const apiTrackedEntities = body.trackedEntities || body.instances || []; cy.get('[data-test="tei-working-lists"]') .find('tr') - .should('have.length', teis.length + 1); + .should('have.length', apiTrackedEntities.length + 1); }); cy.get('@teis') - .then((teis) => { + .then((body) => { + const apiTrackedEntities = body.trackedEntities || body.instances || []; cy.get('[data-test="tei-working-lists"]') .find('tr') .each(($teiRow, index) => { const rowId = $teiRow.get(0).getAttribute('data-test'); if (index > 1) { - expect(rowId).to.equal(teis[index - 1].trackedEntity); + expect(rowId).to.equal(apiTrackedEntities[index - 1].trackedEntity); } }); }); @@ -184,7 +186,7 @@ Then('new teis should be retrieved from the api', () => { .its('response.statusCode') .should('eq', 200); - cy.get('@result').its('response.body.instances').as('teis'); + cy.get('@result').its('response.body').as('teis'); }); @@ -222,7 +224,7 @@ Then('a tei batch capped at 50 records should be retrieved from the api', () => .its('response.url') .should('include', 'page=1'); - cy.get('@result').its('response.body.instances').as('teis'); + cy.get('@result').its('response.body').as('teis'); }); When('you click the first page button on the tei working list', () => { @@ -259,5 +261,5 @@ Then('teis should be retrieved from the api ordered ascendingly by first name', .its('response.url') .should('include', 'page=1'); - cy.get('@result').its('response.body.instances').as('teis'); + cy.get('@result').its('response.body').as('teis'); }); From e4f3399a86cb33d63ac4279e2c2c85d508e1cfdc Mon Sep 17 00:00:00 2001 From: Simona Domnisoru Date: Mon, 29 Jan 2024 14:15:03 +0100 Subject: [PATCH 3/4] feat: handle reactquery key and self contain widgets --- .../DataEntry/FormFoundation/DataElement.js | 10 +++++-- .../DataEntry/helpers/handleAPIResponse.js | 8 ++++++ .../WidgetProfile/DataEntry/helpers/index.js | 1 + .../hooks/useAddRelationship.js | 27 +++++++++++-------- .../epics/getEventListData.js | 1 - .../capture-core/events/eventRequests.js | 2 +- .../relationships/relationshipRequests.js | 2 +- .../utils/api/handleAPIResponse.js | 14 ---------- 8 files changed, 35 insertions(+), 30 deletions(-) create mode 100644 src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/handleAPIResponse.js diff --git a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js index a94775628e..559182f26e 100644 --- a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js +++ b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js @@ -1,7 +1,6 @@ // @flow /* eslint-disable no-underscore-dangle */ import log from 'loglevel'; -import { handleAPIResponse } from 'capture-core/utils/api'; import i18n from '@dhis2/d2-i18n'; import { pipe, errorCreator } from 'capture-core-utils'; @@ -20,7 +19,14 @@ import { convertFormToClient, convertClientToServer } from '../../../../converte import { convertOptionSetValue } from '../../../../converters/serverToClient'; import { buildIcon } from '../../../../metaDataMemoryStoreBuilders/common/helpers'; import { OptionGroup } from '../../../../metaData/OptionSet/OptionGroup'; -import { getFeatureType, getDataElement, getLabel, isNotValidOptionSet, escapeString } from '../helpers'; +import { + getFeatureType, + getDataElement, + getLabel, + isNotValidOptionSet, + escapeString, + handleAPIResponse, +} from '../helpers'; import type { QuerySingleResource } from '../../../../utils/api/api.types'; const OPTION_SET_NOT_FOUND = 'Optionset not found'; diff --git a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/handleAPIResponse.js b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/handleAPIResponse.js new file mode 100644 index 0000000000..8ff870253e --- /dev/null +++ b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/handleAPIResponse.js @@ -0,0 +1,8 @@ +// @flow + +export const handleAPIResponse = (resourceName: string, apiResponse: any) => { + if (!apiResponse) { + return []; + } + return apiResponse[resourceName] || apiResponse.instances || []; +}; diff --git a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/index.js b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/index.js index 9a9b94144a..08be8b975c 100644 --- a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/index.js +++ b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/index.js @@ -16,3 +16,4 @@ export { GEOMETRY, getFeatureType, getDataElement, getLabel } from './geometry'; export { convertClientToView } from './convertClientToView'; export { isNotValidOptionSet } from './isNotValidOptionSet'; export { escapeString } from './escapeString'; +export { handleAPIResponse } from './handleAPIResponse'; diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/hooks/useAddRelationship.js b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/hooks/useAddRelationship.js index 9bdfd4b14d..e007b4184e 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/hooks/useAddRelationship.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/hooks/useAddRelationship.js @@ -1,7 +1,9 @@ // @flow import i18n from '@dhis2/d2-i18n'; +import { FEATURES, useFeature } from 'capture-core-utils'; import { useDataEngine, useAlert } from '@dhis2/app-runtime'; import { useMutation, useQueryClient } from 'react-query'; +import { handleAPIResponse } from 'capture-core/utils/api'; type Props = { teiId: string; @@ -19,6 +21,7 @@ const addRelationshipMutation = { export const useAddRelationship = ({ teiId, onMutate, onSuccess }: Props) => { const queryClient = useQueryClient(); + const queryKey: string = useFeature(FEATURES.exportablePayload) ? 'relationships' : 'instances'; const dataEngine = useDataEngine(); const { show: showSnackbar } = useAlert( i18n.t('An error occurred while adding the relationship'), @@ -36,11 +39,12 @@ export const useAddRelationship = ({ teiId, onMutate, onSuccess }: Props) => { onError: (_, requestData) => { showSnackbar(); const apiRelationshipId = requestData.clientRelationship.relationship; - const currentRelationships = queryClient.getQueryData([ReactQueryAppNamespace, 'relationships', teiId]); + const apiResponse = queryClient.getQueryData([ReactQueryAppNamespace, 'relationships', teiId]); + const apiRelationships = handleAPIResponse('relationships', apiResponse); - if (!currentRelationships?.instances) return; + if (apiRelationships.length === 0) return; - const newRelationships = currentRelationships.instances.reduce((acc, relationship) => { + const newRelationships = apiRelationships.reduce((acc, relationship) => { if (relationship.relationship === apiRelationshipId) { return acc; } @@ -50,7 +54,7 @@ export const useAddRelationship = ({ teiId, onMutate, onSuccess }: Props) => { queryClient.setQueryData( [ReactQueryAppNamespace, 'relationships', teiId], - { instances: newRelationships }, + { [queryKey]: newRelationships }, ); }, onMutate: (...props) => { @@ -58,18 +62,19 @@ export const useAddRelationship = ({ teiId, onMutate, onSuccess }: Props) => { const { clientRelationship } = props[0]; if (!clientRelationship) return; - queryClient.setQueryData([ReactQueryAppNamespace, 'relationships', teiId], (oldData) => { - const instances = oldData?.instances || []; - const updatedInstances = [clientRelationship, ...instances]; - return { instances: updatedInstances }; + queryClient.setQueryData([ReactQueryAppNamespace, 'relationships', teiId], (apiResponse) => { + const apiRelationships = handleAPIResponse('relationships', apiResponse); + const updatedInstances = [clientRelationship, ...apiRelationships]; + return { [queryKey]: updatedInstances }; }); }, onSuccess: async (apiResponse, requestData) => { const apiRelationshipId = apiResponse.bundleReport.typeReportMap.RELATIONSHIP.objectReports[0].uid; const currentRelationships = queryClient.getQueryData([ReactQueryAppNamespace, 'relationships', teiId]); - if (!currentRelationships?.instances) return; + const apiRelationships = handleAPIResponse('relationships', currentRelationships); + if (apiRelationships.length === 0) return; - const newRelationships = currentRelationships.instances.map((relationship) => { + const newRelationships = apiRelationships.map((relationship) => { if (relationship.relationship === apiRelationshipId) { return { ...relationship, @@ -81,7 +86,7 @@ export const useAddRelationship = ({ teiId, onMutate, onSuccess }: Props) => { queryClient.setQueryData( [ReactQueryAppNamespace, 'relationships', teiId], - { instances: newRelationships }, + { [queryKey]: newRelationships }, ); onSuccess && onSuccess(apiResponse, requestData); }, diff --git a/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/epics/getEventListData.js b/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/epics/getEventListData.js index 7884ce257b..8a2a1a7e5c 100644 --- a/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/epics/getEventListData.js +++ b/src/core_modules/capture-core/components/WorkingLists/EventWorkingLists/epics/getEventListData.js @@ -182,7 +182,6 @@ export const getEventListData = async ({ querySingleResource: QuerySingleResource, }) => { const mainColumns = getMainColumns(columnsMetaForDataFetching); - // $FlowFixMe const { eventContainers, pagingData, request } = await getEvents( createApiQueryArgs(queryArgs, mainColumns, categoryCombinationId), absoluteApiPath, diff --git a/src/core_modules/capture-core/events/eventRequests.js b/src/core_modules/capture-core/events/eventRequests.js index 4e400072ca..7e27b20463 100644 --- a/src/core_modules/capture-core/events/eventRequests.js +++ b/src/core_modules/capture-core/events/eventRequests.js @@ -182,7 +182,7 @@ export async function getEvents( }); const apiEvents = handleAPIResponse('events', apiResponse); - const eventContainers = await apiEvents.reduce(async (accEventsPromise, apiEvent) => { + const eventContainers: Array = await apiEvents.reduce(async (accEventsPromise, apiEvent) => { const accEvents = await accEventsPromise; const eventContainer = await convertToClientEvent(apiEvent, absoluteApiPath, querySingleResource); if (eventContainer) { diff --git a/src/core_modules/capture-core/relationships/relationshipRequests.js b/src/core_modules/capture-core/relationships/relationshipRequests.js index 774f0ec487..e9d3bd1046 100644 --- a/src/core_modules/capture-core/relationships/relationshipRequests.js +++ b/src/core_modules/capture-core/relationships/relationshipRequests.js @@ -16,7 +16,7 @@ async function getRelationships( params: queryParams, }); const apiRelationships = handleAPIResponse('relationships', apiResponse); - // $FlowFixMe + // $FlowFixMe[missing-annot] return apiRelationships.map(rel => convertServerRelationshipToClient(rel, relationshipTypes)); } diff --git a/src/core_modules/capture-core/utils/api/handleAPIResponse.js b/src/core_modules/capture-core/utils/api/handleAPIResponse.js index afc29763e0..8ff870253e 100644 --- a/src/core_modules/capture-core/utils/api/handleAPIResponse.js +++ b/src/core_modules/capture-core/utils/api/handleAPIResponse.js @@ -1,18 +1,4 @@ // @flow -import { FEATURES, hasAPISupportForFeature } from 'capture-core-utils'; - -export const handleAPIResponseByMinorVersion = ( - resourceName: string, - apiResponse: any, - minorVersion: string | number, -) => { - if (!apiResponse) { - return []; - } - return hasAPISupportForFeature(minorVersion, FEATURES.exportablePayload) - ? apiResponse[resourceName] || [] - : apiResponse.instances; -}; export const handleAPIResponse = (resourceName: string, apiResponse: any) => { if (!apiResponse) { From ffe6ab0c3ed37f1b4db21f8962bab63bb89568cc Mon Sep 17 00:00:00 2001 From: Simona Domnisoru Date: Tue, 30 Jan 2024 08:46:31 +0100 Subject: [PATCH 4/4] chore: use const --- .../WidgetEventSchedule/hooks/useEventsInOrgUnit.js | 4 ++-- .../WidgetProfile/DataEntry/FormFoundation/DataElement.js | 3 ++- .../WidgetProfile/DataEntry/helpers/handleAPIResponse.js | 6 ++++++ .../components/WidgetProfile/DataEntry/helpers/index.js | 2 +- .../hooks/useAddRelationship.js | 8 ++++---- .../common/useRelationships/useRelationships.js | 4 ++-- .../helpers/getEventListData/getEventListData.js | 6 +++--- .../teiViewEpics/helpers/getTeiListData/getTeiListData.js | 4 ++-- src/core_modules/capture-core/events/eventRequests.js | 4 ++-- .../programs/factory/enrollment/DataElementFactory.js | 4 ++-- .../factory/TrackedEntityType/DataElementFactory.js | 4 ++-- .../capture-core/relationships/relationshipRequests.js | 4 ++-- .../trackedEntityInstanceRequests.js | 4 ++-- .../capture-core/utils/api/handleAPIResponse.js | 6 ++++++ src/core_modules/capture-core/utils/api/index.js | 2 +- 15 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/core_modules/capture-core/components/WidgetEventSchedule/hooks/useEventsInOrgUnit.js b/src/core_modules/capture-core/components/WidgetEventSchedule/hooks/useEventsInOrgUnit.js index 15b3b09c01..c7227e8a81 100644 --- a/src/core_modules/capture-core/components/WidgetEventSchedule/hooks/useEventsInOrgUnit.js +++ b/src/core_modules/capture-core/components/WidgetEventSchedule/hooks/useEventsInOrgUnit.js @@ -1,6 +1,6 @@ // @flow import { useMemo, useEffect } from 'react'; -import { handleAPIResponse } from 'capture-core/utils/api'; +import { handleAPIResponse, REQUESTED_ENTITIES } from 'capture-core/utils/api'; import { useDataQuery } from '@dhis2/app-runtime'; export const useEventsInOrgUnit = (orgUnitId: string, selectedDate: string) => { @@ -32,6 +32,6 @@ export const useEventsInOrgUnit = (orgUnitId: string, selectedDate: string) => { } }, [refetch, orgUnitId, selectedDate]); - const apiEvents = handleAPIResponse('events', data?.events); + const apiEvents = handleAPIResponse(REQUESTED_ENTITIES.events, data?.events); return { error, events: !loading && data ? apiEvents : [] }; }; diff --git a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js index 559182f26e..bc6a9997b6 100644 --- a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js +++ b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/FormFoundation/DataElement.js @@ -26,6 +26,7 @@ import { isNotValidOptionSet, escapeString, handleAPIResponse, + REQUESTED_ENTITIES, } from '../helpers'; import type { QuerySingleResource } from '../../../../utils/api/api.types'; @@ -88,7 +89,7 @@ const buildDataElementUnique = ( }); } return requestPromise.then((result) => { - const apiTrackedEntities = handleAPIResponse('trackedEntities', result); + const apiTrackedEntities = handleAPIResponse(REQUESTED_ENTITIES.trackedEntities, result); const otherTrackedEntityInstances = apiTrackedEntities.filter(item => item.trackedEntity !== contextProps.trackedEntityInstanceId); const trackedEntityInstance = (otherTrackedEntityInstances && otherTrackedEntityInstances[0]) || {}; diff --git a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/handleAPIResponse.js b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/handleAPIResponse.js index 8ff870253e..e7fadf3307 100644 --- a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/handleAPIResponse.js +++ b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/handleAPIResponse.js @@ -1,5 +1,11 @@ // @flow +export const REQUESTED_ENTITIES = Object.freeze({ + events: 'events', + trackedEntities: 'trackedEntities', + relationships: 'relationships', +}); + export const handleAPIResponse = (resourceName: string, apiResponse: any) => { if (!apiResponse) { return []; diff --git a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/index.js b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/index.js index 08be8b975c..f506f5c5d4 100644 --- a/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/index.js +++ b/src/core_modules/capture-core/components/WidgetProfile/DataEntry/helpers/index.js @@ -16,4 +16,4 @@ export { GEOMETRY, getFeatureType, getDataElement, getLabel } from './geometry'; export { convertClientToView } from './convertClientToView'; export { isNotValidOptionSet } from './isNotValidOptionSet'; export { escapeString } from './escapeString'; -export { handleAPIResponse } from './handleAPIResponse'; +export { handleAPIResponse, REQUESTED_ENTITIES } from './handleAPIResponse'; diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/hooks/useAddRelationship.js b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/hooks/useAddRelationship.js index e007b4184e..3342810e0b 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/hooks/useAddRelationship.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/WidgetTrackedEntityRelationship/NewTrackedEntityRelationship/hooks/useAddRelationship.js @@ -3,7 +3,7 @@ import i18n from '@dhis2/d2-i18n'; import { FEATURES, useFeature } from 'capture-core-utils'; import { useDataEngine, useAlert } from '@dhis2/app-runtime'; import { useMutation, useQueryClient } from 'react-query'; -import { handleAPIResponse } from 'capture-core/utils/api'; +import { handleAPIResponse, REQUESTED_ENTITIES } from 'capture-core/utils/api'; type Props = { teiId: string; @@ -40,7 +40,7 @@ export const useAddRelationship = ({ teiId, onMutate, onSuccess }: Props) => { showSnackbar(); const apiRelationshipId = requestData.clientRelationship.relationship; const apiResponse = queryClient.getQueryData([ReactQueryAppNamespace, 'relationships', teiId]); - const apiRelationships = handleAPIResponse('relationships', apiResponse); + const apiRelationships = handleAPIResponse(REQUESTED_ENTITIES.relationships, apiResponse); if (apiRelationships.length === 0) return; @@ -63,7 +63,7 @@ export const useAddRelationship = ({ teiId, onMutate, onSuccess }: Props) => { if (!clientRelationship) return; queryClient.setQueryData([ReactQueryAppNamespace, 'relationships', teiId], (apiResponse) => { - const apiRelationships = handleAPIResponse('relationships', apiResponse); + const apiRelationships = handleAPIResponse(REQUESTED_ENTITIES.relationships, apiResponse); const updatedInstances = [clientRelationship, ...apiRelationships]; return { [queryKey]: updatedInstances }; }); @@ -71,7 +71,7 @@ export const useAddRelationship = ({ teiId, onMutate, onSuccess }: Props) => { onSuccess: async (apiResponse, requestData) => { const apiRelationshipId = apiResponse.bundleReport.typeReportMap.RELATIONSHIP.objectReports[0].uid; const currentRelationships = queryClient.getQueryData([ReactQueryAppNamespace, 'relationships', teiId]); - const apiRelationships = handleAPIResponse('relationships', currentRelationships); + const apiRelationships = handleAPIResponse(REQUESTED_ENTITIES.relationships, currentRelationships); if (apiRelationships.length === 0) return; const newRelationships = apiRelationships.map((relationship) => { diff --git a/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js b/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js index 9634a0a944..fdd63ffa2c 100644 --- a/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js +++ b/src/core_modules/capture-core/components/WidgetsRelationship/common/useRelationships/useRelationships.js @@ -1,6 +1,6 @@ // @flow import { useMemo } from 'react'; -import { handleAPIResponse } from 'capture-core/utils/api'; +import { handleAPIResponse, REQUESTED_ENTITIES } from 'capture-core/utils/api'; import { useApiDataQuery } from '../../../../utils/reactQueryHelpers'; import type { InputRelationshipData, RelationshipTypes } from '../Types'; import { determineLinkedEntity } from '../RelationshipsWidget/useGroupedLinkedEntities'; @@ -35,7 +35,7 @@ export const useRelationships = ({ entityId, searchMode, relationshipTypes }: Pr { enabled: !!entityId, select: (apiResponse: any) => { - const apiRelationships = handleAPIResponse('relationships', apiResponse); + const apiRelationships = handleAPIResponse(REQUESTED_ENTITIES.relationships, apiResponse); if (!relationshipTypes?.length || !apiRelationships?.length) { return []; } diff --git a/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getEventListData/getEventListData.js b/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getEventListData/getEventListData.js index 43c52fa5e2..e12d2d43fb 100644 --- a/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getEventListData/getEventListData.js +++ b/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getEventListData/getEventListData.js @@ -1,5 +1,5 @@ // @flow -import { handleAPIResponse } from 'capture-core/utils/api'; +import { handleAPIResponse, REQUESTED_ENTITIES } from 'capture-core/utils/api'; import { convertToClientEvents } from './convertToClientEvents'; import { getSubvalues, @@ -68,7 +68,7 @@ export const getEventListData = async ( resource: resourceEvents, params: queryArgsEvents, }); - const apiEvents = handleAPIResponse('events', apiEventsResponse); + const apiEvents = handleAPIResponse(REQUESTED_ENTITIES.events, apiEventsResponse); const trackedEntityIds = apiEvents .reduce((acc, { trackedEntity }) => (acc.includes(trackedEntity) ? acc : [...acc, trackedEntity]), []) @@ -82,7 +82,7 @@ export const getEventListData = async ( resource: resourceTEIs, params: queryArgsTEIs, }); - const apiTrackedEntities = handleAPIResponse('trackedEntities', apiTEIResponse); + const apiTrackedEntities = handleAPIResponse(REQUESTED_ENTITIES.trackedEntities, apiTEIResponse); const columnsMetaForDataFetchingArray = getColumnsQueryArgs(columnsMetaForDataFetching); const clientEvents = convertToClientEvents(addTEIsData(apiEvents, apiTrackedEntities), columnsMetaForDataFetchingArray); diff --git a/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getTeiListData/getTeiListData.js b/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getTeiListData/getTeiListData.js index 7829289f32..f13196223e 100644 --- a/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getTeiListData/getTeiListData.js +++ b/src/core_modules/capture-core/components/WorkingLists/TeiWorkingLists/epics/teiViewEpics/helpers/getTeiListData/getTeiListData.js @@ -1,5 +1,5 @@ // @flow -import { handleAPIResponse } from 'capture-core/utils/api'; +import { handleAPIResponse, REQUESTED_ENTITIES } from 'capture-core/utils/api'; import { convertToClientTeis } from './convertToClientTeis'; import { getSubvalues, getApiFilterQueryArgs, getMainApiFilterQueryArgs } from '../getListDataCommon'; import type { RawQueryArgs } from './types'; @@ -46,7 +46,7 @@ export const getTeiListData = async ( resource, params: queryArgs, }); - const apiTrackedEntities = handleAPIResponse('trackedEntities', apiResponse); + const apiTrackedEntities = handleAPIResponse(REQUESTED_ENTITIES.trackedEntities, apiResponse); const columnsMetaForDataFetchingArray = [...columnsMetaForDataFetching.values()]; const clientTeis = convertToClientTeis(apiTrackedEntities, columnsMetaForDataFetchingArray, rawQueryArgs.programId); const clientTeisWithSubvalues = await getSubvalues(querySingleResource, absoluteApiPath)(clientTeis, columnsMetaForDataFetchingArray); diff --git a/src/core_modules/capture-core/events/eventRequests.js b/src/core_modules/capture-core/events/eventRequests.js index 196a257ae5..c8e6ca1695 100644 --- a/src/core_modules/capture-core/events/eventRequests.js +++ b/src/core_modules/capture-core/events/eventRequests.js @@ -1,6 +1,6 @@ // @flow import log from 'loglevel'; -import { handleAPIResponse } from 'capture-core/utils/api'; +import { handleAPIResponse, REQUESTED_ENTITIES } from 'capture-core/utils/api'; import { errorCreator } from 'capture-core-utils'; import { programCollection } from '../metaDataMemoryStores/programCollection/programCollection'; import { convertValue } from '../converters/serverToClient'; @@ -181,7 +181,7 @@ export async function getEvents( params: queryParams, }); - const apiEvents = handleAPIResponse('events', apiResponse); + const apiEvents = handleAPIResponse(REQUESTED_ENTITIES.events, apiResponse); const eventContainers: Array = await apiEvents.reduce(async (accEventsPromise, apiEvent) => { const accEvents = await accEventsPromise; const eventContainer = await convertToClientEvent(apiEvent, absoluteApiPath, querySingleResource); diff --git a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js index 09e8d29c0c..b8591e344d 100644 --- a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js +++ b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/programs/factory/enrollment/DataElementFactory.js @@ -1,7 +1,7 @@ // @flow /* eslint-disable no-underscore-dangle */ import log from 'loglevel'; -import { handleAPIResponse } from 'capture-core/utils/api'; +import { handleAPIResponse, REQUESTED_ENTITIES } from 'capture-core/utils/api'; import i18n from '@dhis2/d2-i18n'; import { pipe, errorCreator } from 'capture-core-utils'; @@ -107,7 +107,7 @@ export class DataElementFactory { } return requestPromise .then((result) => { - const apiTrackedEntities = handleAPIResponse('trackedEntities', result); + const apiTrackedEntities = handleAPIResponse(REQUESTED_ENTITIES.trackedEntities, result); const otherTrackedEntityInstances = apiTrackedEntities.filter(item => item.trackedEntity !== contextProps.trackedEntityInstanceId); const trackedEntityInstance = (otherTrackedEntityInstances && otherTrackedEntityInstances[0]) || {}; diff --git a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js index 0ffecd6da5..c9dd2b7c69 100644 --- a/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js +++ b/src/core_modules/capture-core/metaDataMemoryStoreBuilders/trackedEntityTypes/factory/TrackedEntityType/DataElementFactory.js @@ -1,7 +1,7 @@ // @flow /* eslint-disable no-underscore-dangle */ import log from 'loglevel'; -import { handleAPIResponse } from 'capture-core/utils/api'; +import { handleAPIResponse, REQUESTED_ENTITIES } from 'capture-core/utils/api'; import i18n from '@dhis2/d2-i18n'; import { pipe, errorCreator } from 'capture-core-utils'; import type { @@ -169,7 +169,7 @@ export class DataElementFactory { } return requestPromise .then((result) => { - const apiTrackedEntities = handleAPIResponse('trackedEntities', result); + const apiTrackedEntities = handleAPIResponse(REQUESTED_ENTITIES.trackedEntities, result); const trackedEntityInstance = apiTrackedEntities[0] || {}; const data = { id: trackedEntityInstance.trackedEntity, diff --git a/src/core_modules/capture-core/relationships/relationshipRequests.js b/src/core_modules/capture-core/relationships/relationshipRequests.js index e9d3bd1046..7507ac43a1 100644 --- a/src/core_modules/capture-core/relationships/relationshipRequests.js +++ b/src/core_modules/capture-core/relationships/relationshipRequests.js @@ -1,5 +1,5 @@ // @flow -import { handleAPIResponse } from 'capture-core/utils/api'; +import { handleAPIResponse, REQUESTED_ENTITIES } from 'capture-core/utils/api'; import { getProgramThrowIfNotFound, EventProgram } from '../metaData'; import type { RelationshipType } from '../metaData'; import type { QuerySingleResource } from '../utils/api/api.types'; @@ -15,7 +15,7 @@ async function getRelationships( resource: 'tracker/relationships', params: queryParams, }); - const apiRelationships = handleAPIResponse('relationships', apiResponse); + const apiRelationships = handleAPIResponse(REQUESTED_ENTITIES.relationships, apiResponse); // $FlowFixMe[missing-annot] return apiRelationships.map(rel => convertServerRelationshipToClient(rel, relationshipTypes)); } diff --git a/src/core_modules/capture-core/trackedEntityInstances/trackedEntityInstanceRequests.js b/src/core_modules/capture-core/trackedEntityInstances/trackedEntityInstanceRequests.js index 6c5b634419..01920797e7 100644 --- a/src/core_modules/capture-core/trackedEntityInstances/trackedEntityInstanceRequests.js +++ b/src/core_modules/capture-core/trackedEntityInstances/trackedEntityInstanceRequests.js @@ -1,5 +1,5 @@ // @flow -import { handleAPIResponse } from 'capture-core/utils/api'; +import { handleAPIResponse, REQUESTED_ENTITIES } from 'capture-core/utils/api'; import { type DataElement, convertDataElementsValues } from '../metaData'; import { convertValue } from '../converters/serverToClient'; import { getSubValues } from './getSubValues'; @@ -68,7 +68,7 @@ export async function getTrackedEntityInstances( resource: 'tracker/trackedEntities', params: queryParams, }); - const apiTrackedEntities = handleAPIResponse('trackedEntities', apiResponse); + const apiTrackedEntities = handleAPIResponse(REQUESTED_ENTITIES.trackedEntities, apiResponse); const trackedEntityInstanceContainers = await apiTrackedEntities.reduce(async (accTeiPromise, apiTei) => { const accTeis = await accTeiPromise; diff --git a/src/core_modules/capture-core/utils/api/handleAPIResponse.js b/src/core_modules/capture-core/utils/api/handleAPIResponse.js index 8ff870253e..e7fadf3307 100644 --- a/src/core_modules/capture-core/utils/api/handleAPIResponse.js +++ b/src/core_modules/capture-core/utils/api/handleAPIResponse.js @@ -1,5 +1,11 @@ // @flow +export const REQUESTED_ENTITIES = Object.freeze({ + events: 'events', + trackedEntities: 'trackedEntities', + relationships: 'relationships', +}); + export const handleAPIResponse = (resourceName: string, apiResponse: any) => { if (!apiResponse) { return []; diff --git a/src/core_modules/capture-core/utils/api/index.js b/src/core_modules/capture-core/utils/api/index.js index 1cdfaed41d..97df87a704 100644 --- a/src/core_modules/capture-core/utils/api/index.js +++ b/src/core_modules/capture-core/utils/api/index.js @@ -1,4 +1,4 @@ // @flow export { makeQuerySingleResource } from './makeQuerySingleResource'; -export { handleAPIResponse } from './handleAPIResponse'; +export { handleAPIResponse, REQUESTED_ENTITIES } from './handleAPIResponse'; export type * from './api.types';