Skip to content

Commit 31fd281

Browse files
feat: apply convertSearchFormToServer to relationship search
1 parent 8ca911b commit 31fd281

File tree

8 files changed

+62
-151
lines changed

8 files changed

+62
-151
lines changed

i18n/en.pot

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ msgstr ""
55
"Content-Type: text/plain; charset=utf-8\n"
66
"Content-Transfer-Encoding: 8bit\n"
77
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
8-
"POT-Creation-Date: 2025-12-11T07:56:27.475Z\n"
9-
"PO-Revision-Date: 2025-12-11T07:56:27.475Z\n"
8+
"POT-Creation-Date: 2025-12-15T12:52:54.824Z\n"
9+
"PO-Revision-Date: 2025-12-15T12:52:54.824Z\n"
1010

1111
msgid "Choose one or more dates..."
1212
msgstr "Choose one or more dates..."
@@ -537,6 +537,9 @@ msgstr "Clear"
537537
msgid "No results"
538538
msgstr "No results"
539539

540+
msgid "LIKE - todo delete"
541+
msgstr "LIKE - todo delete"
542+
540543
msgid "Must match the start of the value"
541544
msgstr "Must match the start of the value"
542545

src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TeiSearch/epics/teiSearch.epics.ts

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,7 @@ import { ofType } from 'redux-observable';
44
import { map, takeUntil, switchMap, filter, catchError } from 'rxjs/operators';
55
import { batchActions } from 'redux-batched-actions';
66
import { featureAvailable, FEATURES } from 'capture-core-utils';
7-
import { convertValue as convertToClient } from '../../../../../../converters/formToClient';
8-
import { convertValue as convertToServer } from '../../../../../../converters/clientToServer';
9-
import {
10-
convertValue as convertToFilters,
11-
convertValueToEqual as convertToUniqueFilters,
12-
} from '../serverToFilters';
7+
import { convertSearchFormToServer } from '../../../../../../converters';
138
import {
149
actionTypes,
1510
batchActionTypes,
@@ -106,18 +101,25 @@ const searchTei = ({
106101
selectedOrgUnitScope,
107102
} = currentTeiSearch;
108103

109-
const searchGroups = getSearchGroups(selectedTrackedEntityTypeId, selectedProgramId);
104+
const { searchGroups, attributes } = selectedProgramId
105+
? getTrackerProgram(selectedProgramId)
106+
: getTrackedEntityType(selectedTrackedEntityTypeId);
107+
108+
110109
const searchGroup = searchGroups[searchGroupId];
111-
const filterConverter = searchGroup.unique ? convertToUniqueFilters : convertToFilters;
110+
const searchGroupElements = searchGroup?.searchForm?.getElements();
112111

113-
const filterValues = searchGroup.searchForm.convertValues(formValues,
114-
(value: any, type: any, element: any) =>
115-
filterConverter(convertToServer(convertToClient(value, type), type), type, element));
112+
const filters = Object.keys(formValues)
113+
.map((fieldId) => {
114+
const dataElement = attributes.find(attribute => attribute.id === fieldId);
115+
const searchGroupElement = searchGroupElements?.find(element => element.id === fieldId);
116+
if (formValues[fieldId] && dataElement && searchGroupElement) {
117+
const searchOperator = searchGroupElement.searchOperator;
116118

117-
const filters = Object.keys(filterValues).reduce((accFilters: any[], key) => {
118-
const value = filterValues[key];
119-
return isArray(value) ? [...accFilters, ...value] : [...accFilters, value];
120-
}, []).filter(f => f !== null && f !== undefined);
119+
return convertSearchFormToServer(formValues[fieldId], dataElement, searchOperator);
120+
}
121+
return null;
122+
});
121123

122124
const queryArgs = {
123125
filter: filters,
@@ -128,10 +130,6 @@ const searchTei = ({
128130
pageSize: resultsPageSize,
129131
};
130132

131-
const attributes = selectedProgramId ?
132-
getTrackerProgram(selectedProgramId).attributes :
133-
getTrackedEntityType(selectedTrackedEntityTypeId).attributes;
134-
135133
return from(getTrackedEntityInstances(
136134
queryArgs,
137135
attributes,

src/core_modules/capture-core/components/Pages/common/TEIRelationshipsWidget/TeiSearch/serverToFilters.ts

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/core_modules/capture-core/components/SearchBox/SearchForm/SearchForm.epics.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,10 @@ export const fallbackSearchEpic = (
356356
const availableSearchGroup = searchGroups.find((group: any) => !group.unique);
357357

358358
const filter = getFiltersForAttributesSearchQuery(
359-
fallbackFormValues, // DHIS2-20530 - TODO the fallback value are not in form shape the convertars should not be applied
359+
fallbackFormValues, // will be fixed in DHIS2-20530
360360
attributes,
361361
availableSearchGroup?.searchForm.getElements(),
362-
).filter((query: any) => query);
362+
).filter(Boolean);
363363
const orgUnitModeQueryParam: string = featureAvailable(FEATURES.newOrgUnitModeQueryParam)
364364
? 'orgUnitMode'
365365
: 'ouMode';

src/core_modules/capture-core/components/TeiSearch/epics/teiSearch.epics.ts

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@ import { map, takeUntil, switchMap, filter, catchError } from 'rxjs/operators';
55
import { batchActions } from 'redux-batched-actions';
66
import { featureAvailable, FEATURES } from 'capture-core-utils';
77
import type { ApiUtils, ReduxStore } from 'capture-core-utils/types';
8-
import { convertValue as convertToClient } from '../../../converters/formToClient';
9-
import { convertValue as convertToServer } from '../../../converters/clientToServer';
10-
import {
11-
convertValue as convertToFilters,
12-
convertValueToEqual as convertToUniqueFilters,
13-
} from '../serverToFilters';
8+
import { convertSearchFormToServer } from '../../../converters';
149
import {
1510
actionTypes,
1611
batchActionTypes,
@@ -109,18 +104,25 @@ const searchTei = ({
109104
selectedOrgUnitScope,
110105
} = currentTeiSearch;
111106

112-
const searchGroups = getSearchGroups(selectedTrackedEntityTypeId, selectedProgramId);
107+
const { searchGroups, attributes } = selectedProgramId
108+
? getTrackerProgram(selectedProgramId)
109+
: getTrackedEntityType(selectedTrackedEntityTypeId);
110+
111+
113112
const searchGroup = searchGroups[searchGroupId];
114-
const filterConverter = searchGroup.unique ? convertToUniqueFilters : convertToFilters;
113+
const searchGroupElements = searchGroup?.searchForm?.getElements();
115114

116-
const filterValues = searchGroup.searchForm.convertValues(formValues,
117-
(value: any, type: any, element: any) =>
118-
filterConverter(convertToServer(convertToClient(value, type), type), type, element));
115+
const filters = Object.keys(formValues)
116+
.map((fieldId) => {
117+
const dataElement = attributes.find(attribute => attribute.id === fieldId);
118+
const searchGroupElement = searchGroupElements?.find(element => element.id === fieldId);
119+
if (formValues[fieldId] && dataElement && searchGroupElement) {
120+
const searchOperator = searchGroupElement.searchOperator;
119121

120-
const filters = Object.keys(filterValues).reduce((accFilters, key) => {
121-
const value = filterValues[key];
122-
return isArray(value) ? [...accFilters, ...value] : [...accFilters, value];
123-
}, [] as any[]).filter(f => f !== null && f !== undefined);
122+
return convertSearchFormToServer(formValues[fieldId], dataElement, searchOperator);
123+
}
124+
return null;
125+
});
124126

125127
const queryArgs = {
126128
filter: filters,
@@ -131,10 +133,6 @@ const searchTei = ({
131133
pageSize: resultsPageSize,
132134
};
133135

134-
const attributes = selectedProgramId ?
135-
getTrackerProgram(selectedProgramId).attributes :
136-
getTrackedEntityType(selectedTrackedEntityTypeId).attributes;
137-
138136
return from(getTrackedEntityInstances(
139137
queryArgs, attributes, absoluteApiPath, querySingleResource, selectedProgramId,
140138
)).pipe(

src/core_modules/capture-core/components/TeiSearch/serverToFilters.ts

Lines changed: 0 additions & 47 deletions
This file was deleted.

src/core_modules/capture-core/converters/searchFormToServer.ts

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,41 @@ import { convertClientToServer, convertFormToClient } from './index';
66

77
type FormValues = { [key: string]: any };
88

9-
const convertString = (formValues: string, dataElement: DataElement, searchOperator: SearchOperator) => {
10-
const sanitizedString = formValues.trim();
11-
const convertedString = dataElement.convertValue(
12-
sanitizedString,
13-
pipeD2(convertFormToClient, convertClientToServer),
14-
);
9+
const convertValuePipe = pipeD2(convertFormToClient, convertClientToServer);
10+
11+
const convertString = (formValue: string, dataElement: DataElement, searchOperator: SearchOperator) => {
12+
const sanitizedString = formValue.trim();
13+
const convertedString = dataElement.convertValue(sanitizedString, convertValuePipe);
1514
return `${dataElement.id}:${searchOperator.toLowerCase()}:${escapeString(convertedString)}`;
1615
};
1716

1817
const convertRange = (formValues: FormValues, dataElement: DataElement) => {
1918
const { from, to } = formValues;
20-
const convertedFrom = from && dataElement.convertValue(from, pipeD2(convertFormToClient, convertClientToServer));
21-
const convertedTo = to && dataElement.convertValue(to, pipeD2(convertFormToClient, convertClientToServer));
22-
if (from || to) {
23-
return `${dataElement.id}${convertedFrom ? `:ge:${escapeString(String(convertedFrom))}` : ''}${
24-
convertedTo ? `:le:${escapeString(String(convertedTo))}` : ''
25-
}`;
19+
if (!from && !to) {
20+
return null;
2621
}
27-
return null;
22+
23+
const convertedFrom = from && dataElement.convertValue(from, convertValuePipe);
24+
const convertedTo = to && dataElement.convertValue(to, convertValuePipe);
25+
26+
const fromPart = convertedFrom ? `:ge:${escapeString(String(convertedFrom))}` : '';
27+
const toPart = convertedTo ? `:le:${escapeString(String(convertedTo))}` : '';
28+
29+
return `${dataElement.id}${fromPart}${toPart}`;
2830
};
2931

3032
const convertOrgUnit = (formValues: FormValues, dataElement: DataElement, searchOperator: SearchOperator) => {
31-
const convertedId = dataElement.convertValue(formValues, pipeD2(convertFormToClient, convertClientToServer));
33+
const convertedId = dataElement.convertValue(formValues, convertValuePipe);
3234
return `${dataElement.id}:${searchOperator.toLowerCase()}:${convertedId}`;
3335
};
3436

3537
const convertAge = (formValues: FormValues, dataElement: DataElement, searchOperator: SearchOperator) => {
36-
const convertedAge =
37-
formValues && dataElement.convertValue(formValues, pipeD2(convertFormToClient, convertClientToServer));
38+
const convertedAge = formValues && dataElement.convertValue(formValues, convertValuePipe);
3839
return `${dataElement.id}:${searchOperator.toLowerCase()}:${convertedAge}`;
3940
};
4041

41-
const convertBoolean = (formValues: boolean, dataElement: DataElement, searchOperator: SearchOperator) => {
42-
const convertedBool = dataElement.convertValue(formValues, pipeD2(convertFormToClient, convertClientToServer));
42+
const convertBoolean = (formValue: boolean, dataElement: DataElement, searchOperator: SearchOperator) => {
43+
const convertedBool = dataElement.convertValue(formValue, convertValuePipe);
4344
return `${dataElement.id}:${searchOperator.toLowerCase()}:${convertedBool}`;
4445
};
4546

src/core_modules/capture-core/metaDataMemoryStoreBuilders/common/factory/searchGroup/searchOperator/getSearchOperator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import log from 'loglevel';
22
import { errorCreator } from 'capture-core-utils';
3+
import { dataElementTypes } from '../../../../../metaData';
34
import type { CachedTrackedEntityAttribute } from '../../../../../storageControllers';
45
import {
56
DEFAULT_IS_UNIQUE_SEARCH_OPERATOR,
@@ -44,7 +45,7 @@ export const getSearchOperator = (metadata: CachedTrackedEntityAttribute): Searc
4445
if (metadata.unique) {
4546
return DEFAULT_IS_UNIQUE_SEARCH_OPERATOR;
4647
}
47-
if (metadata.optionSet) {
48+
if (metadata.optionSet && metadata.valueType !== dataElementTypes.MULTI_TEXT) {
4849
return DEFAULT_HAS_OPTION_SET_SEARCH_OPERATOR;
4950
}
5051

0 commit comments

Comments
 (0)