@pega/react-sdk-overrides 23.1.11 → 24.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/designSystemExtension/FieldValueList/FieldValueList.tsx +10 -4
- package/lib/field/CancelAlert/CancelAlert.tsx +2 -0
- package/lib/field/Checkbox/Checkbox.tsx +101 -23
- package/lib/field/Currency/Currency.tsx +36 -26
- package/lib/field/Decimal/Decimal.tsx +44 -21
- package/lib/field/Multiselect/Multiselect.tsx +244 -0
- package/lib/field/Multiselect/index.tsx +1 -0
- package/lib/field/Multiselect/utils.ts +230 -0
- package/lib/field/Percentage/Percentage.tsx +33 -18
- package/lib/field/Phone/Phone.tsx +16 -7
- package/lib/field/RichText/RichText.tsx +2 -2
- package/lib/field/ScalarList/ScalarList.tsx +2 -0
- package/lib/field/UserReference/UserReference.tsx +11 -1
- package/lib/helpers/common-utils.ts +1 -5
- package/lib/helpers/instructions-utils.ts +38 -0
- package/lib/infra/Assignment/Assignment.tsx +28 -1
- package/lib/infra/Containers/FlowContainer/FlowContainer.tsx +5 -3
- package/lib/infra/DashboardFilter/DashboardFilter.tsx +1 -1
- package/lib/infra/DeferLoad/DeferLoad.tsx +5 -1
- package/lib/infra/MultiStep/MultiStep.tsx +3 -1
- package/lib/infra/NavBar/NavBar.tsx +1 -1
- package/lib/infra/Reference/Reference.tsx +1 -1
- package/lib/template/CaseView/CaseView.tsx +2 -1
- package/lib/template/CaseViewActionsMenu/CaseViewActionsMenu.tsx +1 -1
- package/lib/template/DataReference/DataReference.tsx +1 -1
- package/lib/template/DefaultForm/utils/index.ts +2 -7
- package/lib/template/Details/Details/Details.tsx +1 -1
- package/lib/template/Details/DetailsThreeColumn/DetailsThreeColumn.tsx +1 -1
- package/lib/template/Details/DetailsTwoColumn/DetailsTwoColumn.tsx +1 -1
- package/lib/template/FieldGroupTemplate/FieldGroupTemplate.tsx +2 -0
- package/lib/template/ListView/ListView.tsx +22 -33
- package/lib/template/MultiReferenceReadOnly/MultiReferenceReadOnly.tsx +1 -1
- package/lib/template/NarrowWide/NarrowWideDetails/NarrowWideDetails.tsx +1 -1
- package/lib/template/PromotedFilters/PromotedFilters.tsx +1 -0
- package/lib/template/SimpleTable/SimpleTableManual/SimpleTableManual.tsx +8 -4
- package/lib/template/SingleReferenceReadOnly/SingleReferenceReadOnly.tsx +1 -1
- package/lib/template/WideNarrow/WideNarrowDetails/WideNarrowDetails.tsx +1 -1
- package/lib/widget/Attachment/Attachment.tsx +3 -2
- package/lib/widget/FileUtility/FileUtility/FileUtility.tsx +1 -1
- package/lib/widget/QuickCreate/QuickCreate.tsx +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { Checkbox, TextField } from '@material-ui/core';
|
|
2
|
+
import Autocomplete from '@material-ui/lab/Autocomplete';
|
|
3
|
+
import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
|
|
4
|
+
import CheckBoxIcon from '@material-ui/icons/CheckBox';
|
|
5
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
6
|
+
import { doSearch, getDisplayFieldsMetaData, useDeepMemo, preProcessColumns, getGroupDataForItemsTree } from './utils';
|
|
7
|
+
import { insertInstruction, deleteInstruction } from '@pega/react-sdk-components/lib/components/helpers/instructions-utils';
|
|
8
|
+
import { debounce } from 'throttle-debounce';
|
|
9
|
+
|
|
10
|
+
const icon = <CheckBoxOutlineBlankIcon fontSize='small' />;
|
|
11
|
+
const checkedIcon = <CheckBoxIcon fontSize='small' />;
|
|
12
|
+
|
|
13
|
+
export default function Multiselect(props) {
|
|
14
|
+
const {
|
|
15
|
+
getPConnect,
|
|
16
|
+
label,
|
|
17
|
+
placeholder,
|
|
18
|
+
referenceList,
|
|
19
|
+
selectionKey,
|
|
20
|
+
primaryField,
|
|
21
|
+
initialCaseClass,
|
|
22
|
+
showSecondaryInSearchOnly = false,
|
|
23
|
+
listType = '',
|
|
24
|
+
isGroupData = false,
|
|
25
|
+
referenceType,
|
|
26
|
+
secondaryFields,
|
|
27
|
+
groupDataSource = [],
|
|
28
|
+
parameters = {},
|
|
29
|
+
matchPosition = 'contains',
|
|
30
|
+
maxResultsDisplay,
|
|
31
|
+
groupColumnsConfig = [{}],
|
|
32
|
+
selectionList,
|
|
33
|
+
value
|
|
34
|
+
} = props;
|
|
35
|
+
let { datasource = [], columns = [{}] } = props;
|
|
36
|
+
|
|
37
|
+
if (referenceList.length > 0) {
|
|
38
|
+
datasource = referenceList;
|
|
39
|
+
columns = [
|
|
40
|
+
{
|
|
41
|
+
value: primaryField,
|
|
42
|
+
display: 'true',
|
|
43
|
+
useForSearch: true,
|
|
44
|
+
primary: 'true'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
value: selectionKey,
|
|
48
|
+
setProperty: selectionKey,
|
|
49
|
+
key: 'true'
|
|
50
|
+
}
|
|
51
|
+
];
|
|
52
|
+
let secondaryColumns: any = [];
|
|
53
|
+
if (secondaryFields) {
|
|
54
|
+
secondaryColumns = secondaryFields.map(secondaryField => ({
|
|
55
|
+
value: secondaryField,
|
|
56
|
+
display: 'true',
|
|
57
|
+
secondary: 'true',
|
|
58
|
+
useForSearch: 'true'
|
|
59
|
+
}));
|
|
60
|
+
} else {
|
|
61
|
+
secondaryColumns = [
|
|
62
|
+
{
|
|
63
|
+
value: selectionKey,
|
|
64
|
+
display: 'true',
|
|
65
|
+
secondary: 'true',
|
|
66
|
+
useForSearch: 'true'
|
|
67
|
+
}
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
if (referenceType === 'Case') {
|
|
71
|
+
columns = [...columns, ...secondaryColumns];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const [inputValue, setInputValue] = useState(value);
|
|
75
|
+
const [selectedItems, setSelectedItems] = useState([]);
|
|
76
|
+
|
|
77
|
+
const dataConfig = useDeepMemo(() => {
|
|
78
|
+
return {
|
|
79
|
+
dataSource: datasource,
|
|
80
|
+
groupDataSource,
|
|
81
|
+
isGroupData,
|
|
82
|
+
showSecondaryInSearchOnly,
|
|
83
|
+
parameters,
|
|
84
|
+
matchPosition,
|
|
85
|
+
listType,
|
|
86
|
+
maxResultsDisplay: maxResultsDisplay || '100',
|
|
87
|
+
columns: preProcessColumns(columns),
|
|
88
|
+
groupColumnsConfig: preProcessColumns(groupColumnsConfig)
|
|
89
|
+
};
|
|
90
|
+
}, [
|
|
91
|
+
datasource,
|
|
92
|
+
groupDataSource,
|
|
93
|
+
isGroupData,
|
|
94
|
+
showSecondaryInSearchOnly,
|
|
95
|
+
parameters,
|
|
96
|
+
matchPosition,
|
|
97
|
+
listType,
|
|
98
|
+
maxResultsDisplay,
|
|
99
|
+
columns,
|
|
100
|
+
groupColumnsConfig
|
|
101
|
+
]);
|
|
102
|
+
const groupsDisplayFieldMeta = useMemo(
|
|
103
|
+
() => (listType !== 'associated' ? getDisplayFieldsMetaData(dataConfig.groupColumnsConfig) : null),
|
|
104
|
+
[dataConfig.groupColumnsConfig]
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const itemsTreeBaseData = getGroupDataForItemsTree(groupDataSource, groupsDisplayFieldMeta, showSecondaryInSearchOnly) || [];
|
|
108
|
+
|
|
109
|
+
const [itemsTree, setItemsTree] = useState(
|
|
110
|
+
isGroupData ? getGroupDataForItemsTree(groupDataSource, groupsDisplayFieldMeta, showSecondaryInSearchOnly) : []
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const displayFieldMeta = listType !== 'associated' ? getDisplayFieldsMetaData(dataConfig.columns) : null;
|
|
114
|
+
const getCaseListBasedOnParamsDebounced: any = useRef();
|
|
115
|
+
const pConn = getPConnect();
|
|
116
|
+
const contextName = pConn.getContextName();
|
|
117
|
+
const listActions = pConn.getListActions();
|
|
118
|
+
const dataApiObj: any = useRef();
|
|
119
|
+
|
|
120
|
+
// main search function trigger
|
|
121
|
+
const getCaseListBasedOnParams = async (searchText, group, selectedRows, currentItemsTree, isTriggeredFromSearch = false) => {
|
|
122
|
+
if (referenceList && referenceList.length > 0) {
|
|
123
|
+
selectedRows = await listActions.getSelectedRows(true);
|
|
124
|
+
|
|
125
|
+
selectedRows =
|
|
126
|
+
selectedRows &&
|
|
127
|
+
selectedRows.map(item => {
|
|
128
|
+
return {
|
|
129
|
+
id: item[selectionKey.startsWith('.') ? selectionKey.substring(1) : selectionKey],
|
|
130
|
+
primary: item[primaryField.startsWith('.') ? primaryField.substring(1) : primaryField]
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
setSelectedItems(selectedRows);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// if items tree is null or text search is triggered then always should use fresh data object, we use the original object
|
|
137
|
+
const initalItemsTree = isTriggeredFromSearch || !currentItemsTree ? [...itemsTreeBaseData] : [...currentItemsTree];
|
|
138
|
+
const res = await doSearch(
|
|
139
|
+
searchText,
|
|
140
|
+
group,
|
|
141
|
+
initialCaseClass,
|
|
142
|
+
displayFieldMeta,
|
|
143
|
+
dataApiObj.current,
|
|
144
|
+
initalItemsTree,
|
|
145
|
+
isGroupData,
|
|
146
|
+
showSecondaryInSearchOnly,
|
|
147
|
+
selectedRows || []
|
|
148
|
+
);
|
|
149
|
+
setItemsTree(res);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (referenceList && referenceList.length > 0) {
|
|
154
|
+
pConn.setReferenceList(selectionList);
|
|
155
|
+
}
|
|
156
|
+
}, [pConn]);
|
|
157
|
+
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
getCaseListBasedOnParamsDebounced.current = debounce(500, getCaseListBasedOnParams);
|
|
160
|
+
}, []);
|
|
161
|
+
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (listType !== 'associated') {
|
|
164
|
+
PCore.getDataApi()
|
|
165
|
+
?.init(dataConfig, contextName)
|
|
166
|
+
.then(dataObj => {
|
|
167
|
+
dataApiObj.current = dataObj;
|
|
168
|
+
if (!isGroupData) {
|
|
169
|
+
getCaseListBasedOnParamsDebounced.current(inputValue ?? '', '', [...selectedItems], [...itemsTree]);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}, [dataConfig, listType, dataConfig.columns, inputValue, dataConfig.groupColumnsConfig, showSecondaryInSearchOnly]);
|
|
174
|
+
|
|
175
|
+
const onSearchHandler = ev => {
|
|
176
|
+
const searchText = ev.target.value;
|
|
177
|
+
setInputValue(searchText);
|
|
178
|
+
getCaseListBasedOnParamsDebounced.current(searchText, '', [...selectedItems], [...itemsTree], true);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const setSelectedItemsForReferenceList = item => {
|
|
182
|
+
// Clear error messages if any
|
|
183
|
+
const propName = pConn.getStateProps().selectionList;
|
|
184
|
+
pConn.clearErrorMessages({
|
|
185
|
+
property: propName
|
|
186
|
+
});
|
|
187
|
+
const { selected } = item;
|
|
188
|
+
if (selected) {
|
|
189
|
+
insertInstruction(pConn, selectionList, selectionKey, primaryField, item);
|
|
190
|
+
} else {
|
|
191
|
+
deleteInstruction(pConn, selectionList, selectionKey, item);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const handleChange = (event, newSelectedValues) => {
|
|
196
|
+
let clickedItem;
|
|
197
|
+
let updatedItems: any = [];
|
|
198
|
+
if (newSelectedValues && newSelectedValues.length > 0) {
|
|
199
|
+
updatedItems = newSelectedValues.map(ele => {
|
|
200
|
+
ele.selected = true;
|
|
201
|
+
return ele;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
if (newSelectedValues.length > selectedItems.length) {
|
|
205
|
+
clickedItem = newSelectedValues.filter(item => !selectedItems.some((ele: any) => ele.id === item.id));
|
|
206
|
+
} else {
|
|
207
|
+
clickedItem = selectedItems.filter((item: any) => !newSelectedValues.some((ele: any) => ele.id === item.id));
|
|
208
|
+
clickedItem[0].selected = false;
|
|
209
|
+
}
|
|
210
|
+
itemsTree.forEach(ele => {
|
|
211
|
+
ele.selected = !!updatedItems.find(item => item.id === ele.id);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
setSelectedItems(updatedItems);
|
|
215
|
+
setItemsTree(itemsTree);
|
|
216
|
+
|
|
217
|
+
setInputValue('');
|
|
218
|
+
|
|
219
|
+
// if this is a referenceList case
|
|
220
|
+
if (referenceList) setSelectedItemsForReferenceList(clickedItem[0]);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<Autocomplete
|
|
225
|
+
multiple
|
|
226
|
+
fullWidth
|
|
227
|
+
options={itemsTree}
|
|
228
|
+
disableCloseOnSelect
|
|
229
|
+
getOptionSelected={(option: any, val: any) => option?.primary === val?.primary}
|
|
230
|
+
getOptionLabel={(option: any) => option?.primary}
|
|
231
|
+
onChange={handleChange}
|
|
232
|
+
value={selectedItems}
|
|
233
|
+
renderOption={(option: any, { selected }) => (
|
|
234
|
+
<>
|
|
235
|
+
<Checkbox icon={icon} checkedIcon={checkedIcon} style={{ marginRight: 8 }} checked={selected} />
|
|
236
|
+
{option.primary}
|
|
237
|
+
</>
|
|
238
|
+
)}
|
|
239
|
+
renderInput={params => (
|
|
240
|
+
<TextField {...params} variant='outlined' fullWidth label={label} placeholder={placeholder} size='small' onChange={onSearchHandler} />
|
|
241
|
+
)}
|
|
242
|
+
/>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Multiselect';
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
import equal from 'fast-deep-equal';
|
|
3
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
4
|
+
import { updateNewInstuctions, insertInstruction, deleteInstruction } from '@pega/react-sdk-components/lib/components/helpers/instructions-utils';
|
|
5
|
+
|
|
6
|
+
export const setVisibilityForList = (c11nEnv, visibility) => {
|
|
7
|
+
const { selectionMode, selectionList, renderMode, referenceList } = c11nEnv.getComponentConfig();
|
|
8
|
+
// usecase:multiselect, fieldgroup, editable table
|
|
9
|
+
if ((selectionMode === PCore.getConstants().LIST_SELECTION_MODE.MULTI && selectionList) || (renderMode === 'Editable' && referenceList)) {
|
|
10
|
+
c11nEnv.getListActions().setVisibility(visibility);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const useDeepMemo = (memoFn, key) => {
|
|
15
|
+
const ref: any = useRef();
|
|
16
|
+
if (!ref.current || !equal(key, ref.current.key)) {
|
|
17
|
+
ref.current = { key, value: memoFn() };
|
|
18
|
+
}
|
|
19
|
+
return ref.current.value;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const preProcessColumns = columns => {
|
|
23
|
+
return columns?.map(col => {
|
|
24
|
+
const tempColObj = { ...col };
|
|
25
|
+
tempColObj.value = col.value && col.value.startsWith('.') ? col.value.substring(1) : col.value;
|
|
26
|
+
if (tempColObj.setProperty) {
|
|
27
|
+
tempColObj.setProperty = col.setProperty && col.setProperty.startsWith('.') ? col.setProperty.substring(1) : col.setProperty;
|
|
28
|
+
}
|
|
29
|
+
return tempColObj;
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const getDisplayFieldsMetaData = columns => {
|
|
34
|
+
const displayColumns = columns?.filter(col => col.display === 'true');
|
|
35
|
+
const metaDataObj: any = {
|
|
36
|
+
key: '',
|
|
37
|
+
primary: '',
|
|
38
|
+
secondary: []
|
|
39
|
+
};
|
|
40
|
+
const keyCol = columns?.filter(col => col.key === 'true');
|
|
41
|
+
metaDataObj.key = keyCol?.length > 0 ? keyCol[0].value : 'auto';
|
|
42
|
+
const itemsRecordsColumn = columns?.filter(col => col.itemsRecordsColumn === 'true');
|
|
43
|
+
if (itemsRecordsColumn?.length > 0) {
|
|
44
|
+
metaDataObj.itemsRecordsColumn = itemsRecordsColumn[0].value;
|
|
45
|
+
}
|
|
46
|
+
const itemsGroupKeyColumn = columns?.filter(col => col.itemsGroupKeyColumn === 'true');
|
|
47
|
+
if (itemsGroupKeyColumn?.length > 0) {
|
|
48
|
+
metaDataObj.itemsGroupKeyColumn = itemsGroupKeyColumn[0].value;
|
|
49
|
+
}
|
|
50
|
+
for (let index = 0; index < displayColumns?.length; index += 1) {
|
|
51
|
+
if (displayColumns[index].secondary === 'true') {
|
|
52
|
+
metaDataObj.secondary.push(displayColumns[index].value);
|
|
53
|
+
} else if (displayColumns[index].primary === 'true') {
|
|
54
|
+
metaDataObj.primary = displayColumns[index].value;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return metaDataObj;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const createSingleTreeObejct = (entry, displayFieldMeta, showSecondaryData, selected) => {
|
|
61
|
+
const secondaryArr: any = [];
|
|
62
|
+
displayFieldMeta.secondary.forEach(col => {
|
|
63
|
+
secondaryArr.push(entry[col]);
|
|
64
|
+
});
|
|
65
|
+
const isSelected = selected.some(item => item.id === entry[displayFieldMeta.key]);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
id: entry[displayFieldMeta.key],
|
|
69
|
+
primary: entry[displayFieldMeta.primary],
|
|
70
|
+
secondary: showSecondaryData ? secondaryArr : [],
|
|
71
|
+
selected: isSelected
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const putItemsDataInItemsTree = (listObjData, displayFieldMeta, itemsTree, showSecondaryInSearchOnly, selected) => {
|
|
76
|
+
let newTreeItems = itemsTree.slice();
|
|
77
|
+
const showSecondaryData = !showSecondaryInSearchOnly;
|
|
78
|
+
for (const obj of listObjData) {
|
|
79
|
+
const items = obj[displayFieldMeta.itemsRecordsColumn].map(entry => createSingleTreeObejct(entry, displayFieldMeta, showSecondaryData, selected));
|
|
80
|
+
|
|
81
|
+
newTreeItems = newTreeItems.map(caseObject => {
|
|
82
|
+
if (caseObject.id === obj[displayFieldMeta.itemsGroupKeyColumn]) {
|
|
83
|
+
caseObject.items = [...items];
|
|
84
|
+
}
|
|
85
|
+
return caseObject;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return newTreeItems;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const prepareSearchResults = (listObjData, displayFieldMeta) => {
|
|
92
|
+
const searchResults: any = [];
|
|
93
|
+
for (const obj of listObjData) {
|
|
94
|
+
searchResults.push(...obj[displayFieldMeta.itemsRecordsColumn]);
|
|
95
|
+
}
|
|
96
|
+
return searchResults;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const doSearch = async (
|
|
100
|
+
searchText,
|
|
101
|
+
clickedGroup,
|
|
102
|
+
initialCaseClass,
|
|
103
|
+
displayFieldMeta,
|
|
104
|
+
dataApiObj, // deep clone of the dataApiObj
|
|
105
|
+
itemsTree,
|
|
106
|
+
isGroupData,
|
|
107
|
+
showSecondaryInSearchOnly,
|
|
108
|
+
selected
|
|
109
|
+
) => {
|
|
110
|
+
let searchTextForUngroupedData = '';
|
|
111
|
+
if (dataApiObj) {
|
|
112
|
+
// creating dataApiObject in grouped data cases
|
|
113
|
+
if (isGroupData) {
|
|
114
|
+
dataApiObj = cloneDeep(dataApiObj);
|
|
115
|
+
dataApiObj.fetchedNQData = false;
|
|
116
|
+
dataApiObj.cache = {};
|
|
117
|
+
|
|
118
|
+
// if we have no search text and no group selected, return the original tree
|
|
119
|
+
if (searchText === '' && clickedGroup === '') {
|
|
120
|
+
return itemsTree;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// setting the inital search text & search classes in ApiObject
|
|
124
|
+
dataApiObj.parameters[Object.keys(dataApiObj.parameters)[1]] = searchText;
|
|
125
|
+
dataApiObj.parameters[Object.keys(dataApiObj.parameters)[0]] = initialCaseClass;
|
|
126
|
+
|
|
127
|
+
// if we have a selected group
|
|
128
|
+
if (clickedGroup) {
|
|
129
|
+
// check if the data for this group is already present and no search text
|
|
130
|
+
if (searchText === '') {
|
|
131
|
+
const containsData = itemsTree.find(item => item.id === clickedGroup);
|
|
132
|
+
// do not make API call when items of respective group are already fetched
|
|
133
|
+
if (containsData?.items?.length) return itemsTree;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
dataApiObj.parameters[Object.keys(dataApiObj.parameters)[0]] = JSON.stringify([clickedGroup]);
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
searchTextForUngroupedData = searchText;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// search API call
|
|
143
|
+
const response = await dataApiObj.fetchData(searchTextForUngroupedData).catch(() => {
|
|
144
|
+
return itemsTree;
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
let listObjData = response.data;
|
|
148
|
+
let newItemsTree = [];
|
|
149
|
+
if (isGroupData) {
|
|
150
|
+
if (searchText) {
|
|
151
|
+
listObjData = prepareSearchResults(listObjData, displayFieldMeta);
|
|
152
|
+
} else {
|
|
153
|
+
newItemsTree = putItemsDataInItemsTree(listObjData, displayFieldMeta, itemsTree, showSecondaryInSearchOnly, selected);
|
|
154
|
+
return newItemsTree;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const showSecondaryData = showSecondaryInSearchOnly ? !!searchText : true;
|
|
158
|
+
if (listObjData !== undefined && listObjData.length > 0) {
|
|
159
|
+
newItemsTree = listObjData.map(entry => createSingleTreeObejct(entry, displayFieldMeta, showSecondaryData, selected));
|
|
160
|
+
}
|
|
161
|
+
return newItemsTree;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return itemsTree;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const setValuesToPropertyList = (searchText, assocProp, items, columns, actions, updatePropertyInRedux = true) => {
|
|
168
|
+
const setPropertyList = columns
|
|
169
|
+
?.filter(col => col.setProperty)
|
|
170
|
+
.map(col => {
|
|
171
|
+
return {
|
|
172
|
+
source: col.value,
|
|
173
|
+
target: col.setProperty,
|
|
174
|
+
key: col.key,
|
|
175
|
+
primary: col.primary
|
|
176
|
+
};
|
|
177
|
+
});
|
|
178
|
+
const valueToSet: any = [];
|
|
179
|
+
if (setPropertyList.length > 0) {
|
|
180
|
+
setPropertyList.forEach(prop => {
|
|
181
|
+
items.forEach(item => {
|
|
182
|
+
if (prop.key === 'true' && item) {
|
|
183
|
+
valueToSet.push(item.id);
|
|
184
|
+
} else if (prop.primary === 'true' || !item) {
|
|
185
|
+
valueToSet.push(searchText);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
if (updatePropertyInRedux) {
|
|
190
|
+
// BUG-666851 setting options so that the store values are replaced and not merged
|
|
191
|
+
const options = {
|
|
192
|
+
isArrayDeepMerge: false
|
|
193
|
+
};
|
|
194
|
+
if (prop.target === 'Associated property') {
|
|
195
|
+
actions.updateFieldValue(assocProp, valueToSet, options);
|
|
196
|
+
} else {
|
|
197
|
+
actions.updateFieldValue(`.${prop.target}`, valueToSet, options);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return valueToSet;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const getGroupDataForItemsTree = (groupDataSource, groupsDisplayFieldMeta, showSecondaryInSearchOnly) => {
|
|
206
|
+
return groupDataSource?.map(group => {
|
|
207
|
+
const secondaryArr: any = [];
|
|
208
|
+
groupsDisplayFieldMeta.secondary.forEach(col => {
|
|
209
|
+
secondaryArr.push(group[col]);
|
|
210
|
+
});
|
|
211
|
+
return {
|
|
212
|
+
id: group[groupsDisplayFieldMeta.key],
|
|
213
|
+
primary: group[groupsDisplayFieldMeta.primary],
|
|
214
|
+
secondary: showSecondaryInSearchOnly ? [] : secondaryArr,
|
|
215
|
+
items: []
|
|
216
|
+
};
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
export {
|
|
221
|
+
useDeepMemo,
|
|
222
|
+
preProcessColumns,
|
|
223
|
+
getDisplayFieldsMetaData,
|
|
224
|
+
doSearch,
|
|
225
|
+
setValuesToPropertyList,
|
|
226
|
+
getGroupDataForItemsTree,
|
|
227
|
+
updateNewInstuctions,
|
|
228
|
+
insertInstruction,
|
|
229
|
+
deleteInstruction
|
|
230
|
+
};
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { TextField } from '@material-ui/core';
|
|
2
|
+
import { NumericFormat } from 'react-number-format';
|
|
3
|
+
import { useState } from 'react';
|
|
3
4
|
import { getComponentFromMap } from '@pega/react-sdk-components/lib/bridge/helpers/sdk_component_map';
|
|
4
5
|
import { PConnFieldProps } from '@pega/react-sdk-components/lib/types/PConnProps';
|
|
5
6
|
import { getCurrencyCharacters, getCurrencyOptions } from '@pega/react-sdk-components/lib/components/field/Currency/currency-utils';
|
|
6
7
|
import handleEvent from '@pega/react-sdk-components/lib/components/helpers/event-utils';
|
|
7
8
|
import { format } from '@pega/react-sdk-components/lib/components/helpers/formatters';
|
|
8
9
|
|
|
9
|
-
/* Using
|
|
10
|
+
/* Using react-number-format component here, since it allows formatting decimal values,
|
|
10
11
|
as per the locale.
|
|
11
12
|
*/
|
|
12
13
|
interface PercentageProps extends PConnFieldProps {
|
|
13
14
|
// If any, enter additional props that only exist on Percentage here
|
|
14
15
|
currencyISOCode?: string;
|
|
16
|
+
showGroupSeparators?: string;
|
|
17
|
+
decimalPrecision?: number;
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
export default function Percentage(props: PercentageProps) {
|
|
@@ -34,9 +37,13 @@ export default function Percentage(props: PercentageProps) {
|
|
|
34
37
|
helperText,
|
|
35
38
|
displayMode,
|
|
36
39
|
hideLabel,
|
|
37
|
-
placeholder
|
|
40
|
+
placeholder,
|
|
41
|
+
showGroupSeparators,
|
|
42
|
+
decimalPrecision
|
|
38
43
|
} = props;
|
|
39
44
|
|
|
45
|
+
const [values, setValues] = useState(value.toString());
|
|
46
|
+
|
|
40
47
|
const pConn = getPConnect();
|
|
41
48
|
const actions = pConn.getActionsApi();
|
|
42
49
|
const propName = (pConn.getStateProps() as any).value;
|
|
@@ -45,7 +52,11 @@ export default function Percentage(props: PercentageProps) {
|
|
|
45
52
|
const theCurrencyOptions = getCurrencyOptions(currencyISOCode);
|
|
46
53
|
const formattedValue = format(value, pConn.getComponentName().toLowerCase(), theCurrencyOptions);
|
|
47
54
|
|
|
48
|
-
|
|
55
|
+
let readOnlyProp = {}; // Note: empty if NOT ReadOnly
|
|
56
|
+
|
|
57
|
+
if (readOnly) {
|
|
58
|
+
readOnlyProp = { readOnly: true };
|
|
59
|
+
}
|
|
49
60
|
|
|
50
61
|
if (displayMode === 'LABELS_LEFT') {
|
|
51
62
|
return <FieldValueList name={hideLabel ? '' : label} value={formattedValue} />;
|
|
@@ -65,12 +76,17 @@ export default function Percentage(props: PercentageProps) {
|
|
|
65
76
|
const theCurrDec = theSymbols.theDecimalIndicator;
|
|
66
77
|
const theCurrSep = theSymbols.theDigitGroupSeparator;
|
|
67
78
|
|
|
68
|
-
function PercentageOnBlur(
|
|
69
|
-
handleEvent(actions, 'changeNblur', propName,
|
|
79
|
+
function PercentageOnBlur() {
|
|
80
|
+
handleEvent(actions, 'changeNblur', propName, values);
|
|
70
81
|
}
|
|
71
82
|
|
|
83
|
+
const handleChange = val => {
|
|
84
|
+
setValues(val.value);
|
|
85
|
+
};
|
|
86
|
+
|
|
72
87
|
return (
|
|
73
|
-
<
|
|
88
|
+
<NumericFormat
|
|
89
|
+
valueIsNumericString
|
|
74
90
|
fullWidth
|
|
75
91
|
variant={readOnly ? 'standard' : 'outlined'}
|
|
76
92
|
helperText={helperTextToDisplay}
|
|
@@ -78,20 +94,19 @@ export default function Percentage(props: PercentageProps) {
|
|
|
78
94
|
size='small'
|
|
79
95
|
required={required}
|
|
80
96
|
disabled={disabled}
|
|
81
|
-
readOnly={!!readOnly}
|
|
82
97
|
error={status === 'error'}
|
|
83
98
|
label={label}
|
|
84
|
-
value={
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
textAlign='left'
|
|
88
|
-
InputProps={{
|
|
89
|
-
inputProps: { ...testProp }
|
|
99
|
+
value={values}
|
|
100
|
+
onValueChange={val => {
|
|
101
|
+
handleChange(val);
|
|
90
102
|
}}
|
|
91
|
-
currencySymbol=''
|
|
92
|
-
decimalCharacter={theCurrDec}
|
|
93
|
-
digitGroupSeparator={theCurrSep}
|
|
94
103
|
onBlur={!readOnly ? PercentageOnBlur : undefined}
|
|
104
|
+
decimalSeparator={theCurrDec}
|
|
105
|
+
thousandSeparator={showGroupSeparators ? theCurrSep : ''}
|
|
106
|
+
decimalScale={decimalPrecision}
|
|
107
|
+
suffix='%'
|
|
108
|
+
InputProps={{ ...readOnlyProp, inputProps: { ...testProp } }}
|
|
109
|
+
customInput={TextField}
|
|
95
110
|
/>
|
|
96
111
|
);
|
|
97
112
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import MuiPhoneNumber from 'material-ui-phone-number';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
2
3
|
|
|
3
4
|
import { getComponentFromMap } from '@pega/react-sdk-components/lib/bridge/helpers/sdk_component_map';
|
|
4
5
|
import { PConnFieldProps } from '@pega/react-sdk-components/lib/types/PConnProps';
|
|
6
|
+
import handleEvent from '@pega/react-sdk-components/lib/components/helpers/event-utils';
|
|
5
7
|
|
|
6
8
|
interface PhoneProps extends PConnFieldProps {
|
|
7
9
|
// If any, enter additional props that only exist on Phone here
|
|
@@ -12,6 +14,7 @@ export default function Phone(props: PhoneProps) {
|
|
|
12
14
|
const FieldValueList = getComponentFromMap('FieldValueList');
|
|
13
15
|
|
|
14
16
|
const {
|
|
17
|
+
getPConnect,
|
|
15
18
|
label,
|
|
16
19
|
required,
|
|
17
20
|
disabled,
|
|
@@ -19,7 +22,6 @@ export default function Phone(props: PhoneProps) {
|
|
|
19
22
|
validatemessage,
|
|
20
23
|
status,
|
|
21
24
|
onChange,
|
|
22
|
-
onBlur,
|
|
23
25
|
readOnly,
|
|
24
26
|
testId,
|
|
25
27
|
helperText,
|
|
@@ -27,6 +29,14 @@ export default function Phone(props: PhoneProps) {
|
|
|
27
29
|
hideLabel,
|
|
28
30
|
placeholder
|
|
29
31
|
} = props;
|
|
32
|
+
|
|
33
|
+
const pConn = getPConnect();
|
|
34
|
+
const actions = pConn.getActionsApi();
|
|
35
|
+
const propName = (pConn.getStateProps() as any).value;
|
|
36
|
+
|
|
37
|
+
const [inputValue, setInputValue] = useState(value);
|
|
38
|
+
useEffect(() => setInputValue(value), [value]);
|
|
39
|
+
|
|
30
40
|
const helperTextToDisplay = validatemessage || helperText;
|
|
31
41
|
|
|
32
42
|
let testProp = {};
|
|
@@ -69,15 +79,14 @@ export default function Phone(props: PhoneProps) {
|
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
const handleChange = inputVal => {
|
|
72
|
-
|
|
73
|
-
phoneValue = `+${phoneValue}`;
|
|
74
|
-
onChange({ value: phoneValue });
|
|
82
|
+
setInputValue(inputVal);
|
|
75
83
|
};
|
|
76
84
|
|
|
77
85
|
const handleBlur = event => {
|
|
78
86
|
const phoneValue = event?.target?.value;
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
let phoneNumber = phoneValue.split(' ').slice(1).join();
|
|
88
|
+
phoneNumber = phoneNumber ? `+${phoneValue && phoneValue.replace(/\D+/g, '')}` : '';
|
|
89
|
+
handleEvent(actions, 'changeNblur', propName, phoneNumber);
|
|
81
90
|
};
|
|
82
91
|
|
|
83
92
|
return (
|
|
@@ -94,7 +103,7 @@ export default function Phone(props: PhoneProps) {
|
|
|
94
103
|
onBlur={!readOnly ? handleBlur : undefined}
|
|
95
104
|
error={status === 'error'}
|
|
96
105
|
label={label}
|
|
97
|
-
value={
|
|
106
|
+
value={inputValue}
|
|
98
107
|
InputProps={{ ...testProp }}
|
|
99
108
|
/>
|
|
100
109
|
);
|
|
@@ -24,11 +24,11 @@ export default function RichText(props: RichTextProps) {
|
|
|
24
24
|
const helperTextToDisplay = validatemessage || helperText;
|
|
25
25
|
|
|
26
26
|
if (displayMode === 'LABELS_LEFT') {
|
|
27
|
-
return <FieldValueList name={hideLabel ? '' : label} value={value} />;
|
|
27
|
+
return <FieldValueList name={hideLabel ? '' : label} value={value} isHtml />;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
if (displayMode === 'STACKED_LARGE_VAL') {
|
|
31
|
-
return <FieldValueList name={hideLabel ? '' : label} value={value} variant='stacked' />;
|
|
31
|
+
return <FieldValueList name={hideLabel ? '' : label} value={value} isHtml variant='stacked' />;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
let richTextComponent;
|
|
@@ -36,10 +36,12 @@ export default function ScalarList(props: ScalarListProps) {
|
|
|
36
36
|
{
|
|
37
37
|
type: componentType,
|
|
38
38
|
config: {
|
|
39
|
+
// @ts-ignore - Type '{ readOnly: true; displayInModal: boolean; value: any; displayMode: string; label: string; }' is not assignable to type 'ComponentMetadataConfig'.
|
|
39
40
|
value: scalarValue,
|
|
40
41
|
displayMode: 'LABELS_LEFT',
|
|
41
42
|
label,
|
|
42
43
|
...restProps,
|
|
44
|
+
// @ts-ignore - Type 'string' is not assignable to type 'boolean | undefined'.
|
|
43
45
|
readOnly: 'true'
|
|
44
46
|
}
|
|
45
47
|
},
|