@pega/react-sdk-overrides 23.1.11 → 23.1.12

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.
@@ -109,9 +109,9 @@ export default function CaseSummaryFields(props: CaseSummaryFieldsProps) {
109
109
  label={field.config.label}
110
110
  InputProps={{
111
111
  readOnly: true,
112
+ disableUnderline: true,
112
113
  inputProps: {
113
- style: { cursor: 'pointer' },
114
- disableUnderline: true
114
+ style: { cursor: 'pointer' }
115
115
  }
116
116
  }}
117
117
  />
@@ -9,6 +9,7 @@ interface FieldValueListProps {
9
9
  name?: string;
10
10
  value: any;
11
11
  variant?: string;
12
+ isHtml?: boolean;
12
13
  }
13
14
 
14
15
  const useStyles = makeStyles(theme => ({
@@ -45,7 +46,7 @@ function formatItemValue(value) {
45
46
  }
46
47
 
47
48
  export default function FieldValueList(props: FieldValueListProps) {
48
- const { name, value, variant = 'inline' } = props;
49
+ const { name, value, variant = 'inline', isHtml = false } = props;
49
50
  const classes = useStyles();
50
51
 
51
52
  function getGridItemLabel() {
@@ -63,9 +64,14 @@ export default function FieldValueList(props: FieldValueListProps) {
63
64
 
64
65
  return (
65
66
  <Grid item xs={variant === 'stacked' ? 12 : 6} className={variant === 'stacked' ? classes.noPaddingTop : ''}>
66
- <Typography variant={variant === 'stacked' ? 'h6' : 'body2'} component='span' className={classes.fieldValue}>
67
- {formattedValue}
68
- </Typography>
67
+ {isHtml ? (
68
+ // eslint-disable-next-line react/no-danger
69
+ <div dangerouslySetInnerHTML={{ __html: formattedValue }} />
70
+ ) : (
71
+ <Typography variant={variant === 'stacked' ? 'h6' : 'body2'} component='span' className={classes.fieldValue}>
72
+ {formattedValue}
73
+ </Typography>
74
+ )}
69
75
  </Grid>
70
76
  );
71
77
  }
@@ -1,19 +1,35 @@
1
+ /* eslint-disable react/no-array-index-key */
1
2
  import { useState, useEffect } from 'react';
2
3
  import { Checkbox, FormControl, FormControlLabel, FormGroup, FormHelperText, FormLabel } from '@material-ui/core';
3
4
 
4
5
  import handleEvent from '@pega/react-sdk-components/lib/components/helpers/event-utils';
5
6
  import { getComponentFromMap } from '@pega/react-sdk-components/lib/bridge/helpers/sdk_component_map';
7
+ import { insertInstruction, deleteInstruction, updateNewInstuctions } from '@pega/react-sdk-components/lib/components/helpers/instructions-utils';
6
8
  import { PConnFieldProps } from '@pega/react-sdk-components/lib/types/PConnProps';
9
+ import { makeStyles } from '@material-ui/core/styles';
7
10
 
8
11
  interface CheckboxProps extends Omit<PConnFieldProps, 'value'> {
9
12
  // If any, enter additional props that only exist on Checkbox here
10
13
  value?: boolean;
11
- // eslint-disable-next-line react/no-unused-prop-types
12
14
  caption?: string;
13
15
  trueLabel?: string;
14
16
  falseLabel?: string;
17
+ selectionMode?: string;
18
+ datasource?: any;
19
+ selectionKey?: string;
20
+ selectionList?: any;
21
+ primaryField: string;
22
+ readonlyContextList: any;
23
+ referenceList: string;
15
24
  }
16
25
 
26
+ const useStyles = makeStyles(() => ({
27
+ checkbox: {
28
+ display: 'flex',
29
+ flexDirection: 'column'
30
+ }
31
+ }));
32
+
17
33
  export default function CheckboxComponent(props: CheckboxProps) {
18
34
  // Get emitted components from map (so we can get any override that may exist)
19
35
  const FieldValueList = getComponentFromMap('FieldValueList');
@@ -21,7 +37,8 @@ export default function CheckboxComponent(props: CheckboxProps) {
21
37
  const {
22
38
  getPConnect,
23
39
  label,
24
- value = false,
40
+ caption,
41
+ value,
25
42
  readOnly,
26
43
  testId,
27
44
  required,
@@ -32,22 +49,34 @@ export default function CheckboxComponent(props: CheckboxProps) {
32
49
  displayMode,
33
50
  hideLabel,
34
51
  trueLabel,
35
- falseLabel
52
+ falseLabel,
53
+ selectionMode,
54
+ datasource,
55
+ selectionKey,
56
+ selectionList,
57
+ primaryField,
58
+ referenceList,
59
+ readonlyContextList: selectedvalues
36
60
  } = props;
61
+ const classes = useStyles();
37
62
  const helperTextToDisplay = validatemessage || helperText;
38
-
39
63
  const thePConn = getPConnect();
40
- const theConfigProps = thePConn.getConfigProps() as CheckboxProps;
41
- const caption = theConfigProps.caption;
42
64
  const actionsApi = thePConn.getActionsApi();
43
65
  const propName = (thePConn.getStateProps() as any).value;
44
66
 
45
- const [checked, setChecked] = useState(false);
67
+ const [checked, setChecked] = useState<any>(false);
46
68
  useEffect(() => {
47
69
  // This update theSelectedButton which will update the UI to show the selected button correctly
48
70
  setChecked(value);
49
71
  }, [value]);
50
72
 
73
+ useEffect(() => {
74
+ if (referenceList?.length > 0) {
75
+ thePConn.setReferenceList(selectionList);
76
+ updateNewInstuctions(thePConn, selectionList);
77
+ }
78
+ }, [thePConn]);
79
+
51
80
  if (displayMode === 'LABELS_LEFT') {
52
81
  return <FieldValueList name={hideLabel ? '' : caption} value={value ? trueLabel : falseLabel} />;
53
82
  }
@@ -64,28 +93,77 @@ export default function CheckboxComponent(props: CheckboxProps) {
64
93
  thePConn.getValidationApi().validate(event.target.checked);
65
94
  };
66
95
 
67
- let theCheckbox = <Checkbox color='primary' disabled={disabled} />;
96
+ const handleChangeMultiMode = (event, element) => {
97
+ if (event.target.checked) {
98
+ insertInstruction(thePConn, selectionList, selectionKey, primaryField, {
99
+ id: element.key,
100
+ primary: element.text ?? element.value
101
+ });
102
+ } else {
103
+ deleteInstruction(thePConn, selectionList, selectionKey, {
104
+ id: element.key,
105
+ primary: element.text ?? element.value
106
+ });
107
+ }
108
+ thePConn.clearErrorMessages({
109
+ property: selectionList,
110
+ category: '',
111
+ context: ''
112
+ });
113
+ };
68
114
 
69
- if (readOnly) {
70
- // Workaround for lack of InputProps readOnly from https://github.com/mui-org/material-ui/issues/17043
71
- // Also note that we need to turn off the onChange call in the FormControlLabel wrapper, too. See below!
72
- theCheckbox = <Checkbox value={value || false} readOnly={readOnly} />;
115
+ let theCheckbox;
116
+ const listOfCheckboxes: any = [];
117
+ if (selectionMode === 'multi') {
118
+ const listSourceItems = datasource?.source ?? [];
119
+ const dataField: any = selectionKey?.split?.('.')[1];
120
+ listSourceItems.forEach((element, index) => {
121
+ listOfCheckboxes.push(
122
+ <FormControlLabel
123
+ control={
124
+ <Checkbox
125
+ key={index}
126
+ checked={selectedvalues?.some?.(data => data[dataField] === element.key)}
127
+ onChange={event => handleChangeMultiMode(event, element)}
128
+ onBlur={() => {
129
+ thePConn.getValidationApi().validate(selectedvalues, selectionList);
130
+ }}
131
+ data-testid={`${testId}:${element.value}`}
132
+ />
133
+ }
134
+ key={index}
135
+ label={element.text ?? element.value}
136
+ labelPlacement='end'
137
+ data-test-id={testId}
138
+ />
139
+ );
140
+ });
141
+ theCheckbox = <div className={classes.checkbox}>{listOfCheckboxes}</div>;
142
+ } else {
143
+ theCheckbox = (
144
+ <FormControlLabel
145
+ control={
146
+ <Checkbox
147
+ color='primary'
148
+ checked={checked}
149
+ onChange={!readOnly ? handleChange : undefined}
150
+ onBlur={!readOnly ? handleBlur : undefined}
151
+ value={value}
152
+ disabled={disabled}
153
+ readOnly={readOnly}
154
+ />
155
+ }
156
+ label={caption}
157
+ labelPlacement='end'
158
+ data-test-id={testId}
159
+ />
160
+ );
73
161
  }
74
162
 
75
163
  return (
76
164
  <FormControl required={required} error={status === 'error'}>
77
165
  {!hideLabel && <FormLabel component='legend'>{label}</FormLabel>}
78
- <FormGroup>
79
- <FormControlLabel
80
- control={theCheckbox}
81
- checked={checked}
82
- onChange={!readOnly ? handleChange : undefined}
83
- onBlur={!readOnly ? handleBlur : undefined}
84
- label={caption}
85
- labelPlacement='end'
86
- data-test-id={testId}
87
- />
88
- </FormGroup>
166
+ <FormGroup>{theCheckbox}</FormGroup>
89
167
  <FormHelperText>{helperTextToDisplay}</FormHelperText>
90
168
  </FormControl>
91
169
  );
@@ -15,6 +15,7 @@ interface DecimalProps extends PConnFieldProps {
15
15
  currencyISOCode?: string;
16
16
  decimalPrecision?: number;
17
17
  showGroupSeparators?: string;
18
+ formatter?: string;
18
19
  }
19
20
 
20
21
  export default function Decimal(props: DecimalProps) {
@@ -38,7 +39,8 @@ export default function Decimal(props: DecimalProps) {
38
39
  decimalPrecision = 2,
39
40
  showGroupSeparators = true,
40
41
  testId,
41
- placeholder
42
+ placeholder,
43
+ formatter
42
44
  } = props;
43
45
 
44
46
  const pConn = getPConnect();
@@ -49,9 +51,16 @@ export default function Decimal(props: DecimalProps) {
49
51
  const theSymbols = getCurrencyCharacters(currencyISOCode);
50
52
  const theCurrDec = theSymbols.theDecimalIndicator;
51
53
  const theCurrSep = theSymbols.theDigitGroupSeparator;
54
+ const theCurrSym = theSymbols.theCurrencySymbol;
52
55
 
53
56
  const theCurrencyOptions = getCurrencyOptions(currencyISOCode);
54
- const formattedValue = format(value, pConn.getComponentName().toLowerCase(), theCurrencyOptions);
57
+
58
+ let formattedValue = '';
59
+ if (formatter === 'Currency') {
60
+ formattedValue = format(value, formatter.toLowerCase(), theCurrencyOptions);
61
+ } else {
62
+ formattedValue = format(value, pConn.getComponentName().toLowerCase(), theCurrencyOptions);
63
+ }
55
64
 
56
65
  if (displayMode === 'LABELS_LEFT') {
57
66
  return <FieldValueList name={hideLabel ? '' : label} value={formattedValue} />;
@@ -86,7 +95,7 @@ export default function Decimal(props: DecimalProps) {
86
95
  outputFormat='number'
87
96
  textAlign='left'
88
97
  InputProps={{ inputProps: { ...testProp } }}
89
- currencySymbol=''
98
+ currencySymbol={readOnly && formatter === 'Currency' ? theCurrSym : ''}
90
99
  decimalCharacter={theCurrDec}
91
100
  digitGroupSeparator={showGroupSeparators ? theCurrSep : ''}
92
101
  decimalPlaces={decimalPrecision}
@@ -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 = 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
+ };
@@ -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;
@@ -4,5 +4,5 @@ export function isEmptyObject(obj: Object): boolean {
4
4
 
5
5
  export function isInfinity23OrHigher() {
6
6
  const pCoreVersion = PCore.getPCoreVersion();
7
- return ['8.23.0', '23.1.1'].includes(pCoreVersion);
7
+ return ['8.23.0', '23.1.1', '23.1.2'].includes(pCoreVersion);
8
8
  }
@@ -0,0 +1,38 @@
1
+ const isSelfReferencedProperty = (param, referenceProp) => {
2
+ const [, parentPropName] = param.split('.');
3
+ const referencePropParent = referenceProp?.split('.').pop();
4
+ return parentPropName === referencePropParent;
5
+ };
6
+
7
+ const updateNewInstuctions = (c11nEnv, selectionList) => {
8
+ const { datasource: { parameters = {} } = {} } = c11nEnv.getFieldMetadata(selectionList) || {};
9
+ const compositeKeys: any = [];
10
+ Object.values(parameters).forEach((param: any) => {
11
+ if (isSelfReferencedProperty(param, selectionList)) compositeKeys.push(param.substring(param.lastIndexOf('.') + 1));
12
+ });
13
+ c11nEnv.getListActions().initDefaultPageInstructions(selectionList, compositeKeys);
14
+ };
15
+
16
+ const insertInstruction = (c11nEnv, selectionList, selectionKey, primaryField, item) => {
17
+ const { id, primary } = item;
18
+ const actualProperty = selectionKey.startsWith('.') ? selectionKey.substring(1) : selectionKey;
19
+ const displayProperty = primaryField.startsWith('.') ? primaryField.substring(1) : primaryField;
20
+ const rows = c11nEnv.getValue(`${c11nEnv.getPageReference()}${selectionList}`) || [];
21
+ const startIndex = rows.length;
22
+ const content = {
23
+ [actualProperty]: id,
24
+ [displayProperty]: primary,
25
+ nonFormProperties: actualProperty !== displayProperty ? [displayProperty] : []
26
+ };
27
+ c11nEnv.getListActions().insert(content, startIndex);
28
+ };
29
+
30
+ const deleteInstruction = (c11nEnv, selectionList, selectionKey, item) => {
31
+ const { id } = item;
32
+ const actualProperty = selectionKey.startsWith('.') ? selectionKey.substring(1) : selectionKey;
33
+ const rows = c11nEnv.getValue(`${c11nEnv.getPageReference()}${selectionList}`) || [];
34
+ const index = rows.findIndex(row => row[actualProperty] === id);
35
+ c11nEnv.getListActions().deleteEntry(index);
36
+ };
37
+
38
+ export { updateNewInstuctions, insertInstruction, deleteInstruction };
@@ -249,7 +249,7 @@ export default function NavBar(props: NavBarProps) {
249
249
  <Divider />
250
250
  <List className='marginTopAuto'>
251
251
  <>
252
- <ListItem onClick={navPanelOperatorButtonClick}>
252
+ <ListItem onClick={navPanelOperatorButtonClick} style={{ cursor: 'pointer' }}>
253
253
  <ListItemIcon>
254
254
  <PersonOutlineIcon fontSize='large' />
255
255
  </ListItemIcon>
@@ -36,7 +36,7 @@ export default function Reference(props: ReferenceProps) {
36
36
 
37
37
  // @ts-ignore - Argument of type 'null' is not assignable to parameter of type 'string'.
38
38
  const viewComponent: any = pConnect.createComponent(viewObject, null, null, {
39
- pageReference: context
39
+ pageReference: context && context.startsWith('@CLASS') ? '' : context
40
40
  });
41
41
 
42
42
  viewComponent.props.getPConnect().setInheritedConfig({
@@ -209,10 +209,10 @@ export default function ListView(props: ListViewProps) {
209
209
  };
210
210
 
211
211
  function descendingComparator<T>(a: T, b: T, orderedBy: keyof T) {
212
- if (b[orderedBy] < a[orderedBy]) {
212
+ if (!b[orderedBy] || b[orderedBy] < a[orderedBy]) {
213
213
  return -1;
214
214
  }
215
- if (b[orderedBy] > a[orderedBy]) {
215
+ if (!a[orderedBy] || b[orderedBy] > a[orderedBy]) {
216
216
  return 1;
217
217
  }
218
218
  return 0;
@@ -981,7 +981,7 @@ export default function ListView(props: ListViewProps) {
981
981
  break;
982
982
 
983
983
  default:
984
- val = column.format && typeof value === 'number' ? column.format(value) : value;
984
+ val = column.format && typeof value === 'number' ? column.format(value) : value || '---';
985
985
  }
986
986
  return val;
987
987
  };
@@ -1047,7 +1047,7 @@ export default function ListView(props: ListViewProps) {
1047
1047
  .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
1048
1048
  .map(row => {
1049
1049
  return (
1050
- <TableRow key={row.pxRefObjectInsName || row.pyID}>
1050
+ <TableRow key={row.pxRefObjectInsName || row.pyID || row.pyGUID}>
1051
1051
  {arColumns.map(column => {
1052
1052
  const value = row[column.id];
1053
1053
  return (
@@ -1062,7 +1062,7 @@ export default function ListView(props: ListViewProps) {
1062
1062
  {column.format && typeof value === 'number' ? column.format(value) : value}
1063
1063
  </Link>
1064
1064
  ) : (
1065
- <>{column.format && typeof value === 'number' ? column.format(value) : value}</>
1065
+ <>{column.format && typeof value === 'number' ? column.format(value) : value || '---'}</>
1066
1066
  )}
1067
1067
  </TableCell>
1068
1068
  );
@@ -1104,7 +1104,7 @@ export default function ListView(props: ListViewProps) {
1104
1104
  .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
1105
1105
  .map(row => {
1106
1106
  return (
1107
- <TableRow key={row[rowID]}>
1107
+ <TableRow key={row.pxRefObjectInsName || row.pyGUID || row.pyID}>
1108
1108
  {selectionMode === SELECTION_MODE.SINGLE && (
1109
1109
  <TableCell>
1110
1110
  <Radio
@@ -374,10 +374,10 @@ export default function SimpleTableManual(props: PropsWithChildren<SimpleTableMa
374
374
  };
375
375
 
376
376
  function descendingComparator<T>(a: T, b: T, orderedBy: keyof T) {
377
- if (b[orderedBy] < a[orderedBy]) {
377
+ if (!b[orderedBy] || b[orderedBy] < a[orderedBy]) {
378
378
  return -1;
379
379
  }
380
- if (b[orderedBy] > a[orderedBy]) {
380
+ if (!a[orderedBy] || b[orderedBy] > a[orderedBy]) {
381
381
  return 1;
382
382
  }
383
383
  return 0;
@@ -588,7 +588,7 @@ export default function SimpleTableManual(props: PropsWithChildren<SimpleTableMa
588
588
  direction={orderBy === displayedColumns[index] ? order : 'asc'}
589
589
  onClick={createSortHandler(displayedColumns[index])}
590
590
  >
591
- {field.label}
591
+ {field.label || '---'}
592
592
  {_showFilteredIcon(field.name) && <FilterListIcon className={classes.moreIcon} />}
593
593
  {orderBy === displayedColumns[index] ? (
594
594
  <span className={classes.visuallyHidden}>{order === 'desc' ? 'sorted descending' : 'sorted ascending'}</span>
@@ -671,7 +671,7 @@ export default function SimpleTableManual(props: PropsWithChildren<SimpleTableMa
671
671
  ) : typeof row[colKey] === 'boolean' && row[colKey] ? (
672
672
  'True'
673
673
  ) : (
674
- row[colKey]
674
+ row[colKey] || '---'
675
675
  )}
676
676
  </TableCell>
677
677
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pega/react-sdk-overrides",
3
- "version": "23.1.11",
3
+ "version": "23.1.12",
4
4
  "description": "React SDK - Code for overriding components",
5
5
  "_filesComment": "During packing, npm ignores everything NOT in the files list",
6
6
  "files": [