@pega/react-sdk-overrides 24.2.11 → 25.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.
Files changed (164) hide show
  1. package/lib/designSystemExtension/Banner/Banner.css +1 -1
  2. package/lib/designSystemExtension/Banner/Banner.tsx +10 -7
  3. package/lib/designSystemExtension/CaseSummaryFields/CaseSummaryFields.css +0 -1
  4. package/lib/designSystemExtension/CaseSummaryFields/CaseSummaryFields.tsx +53 -37
  5. package/lib/designSystemExtension/DetailsFields/DetailsFields.tsx +11 -13
  6. package/lib/designSystemExtension/FieldGroup/FieldGroup.tsx +8 -9
  7. package/lib/designSystemExtension/FieldGroupList/FieldGroupList.tsx +9 -9
  8. package/lib/designSystemExtension/FieldValueList/FieldValueList.tsx +7 -8
  9. package/lib/designSystemExtension/Operator/Operator.tsx +21 -19
  10. package/lib/designSystemExtension/Pulse/Pulse.tsx +1 -1
  11. package/lib/designSystemExtension/RichTextEditor/RichTextEditor.tsx +32 -4
  12. package/lib/designSystemExtension/WssQuickCreate/WssQuickCreate.css +7 -14
  13. package/lib/designSystemExtension/WssQuickCreate/WssQuickCreate.tsx +13 -2
  14. package/lib/field/AutoComplete/AutoComplete.tsx +1 -1
  15. package/lib/field/CancelAlert/CancelAlert.css +4 -4
  16. package/lib/field/CancelAlert/CancelAlert.tsx +6 -6
  17. package/lib/field/Checkbox/Checkbox.tsx +97 -4
  18. package/lib/field/Currency/Currency.tsx +3 -3
  19. package/lib/field/Currency/currency-utils.ts +1 -2
  20. package/lib/field/Date/Date.tsx +3 -7
  21. package/lib/field/DateTime/DateTime.tsx +3 -8
  22. package/lib/field/Decimal/Decimal.tsx +3 -5
  23. package/lib/field/Dropdown/Dropdown.tsx +5 -7
  24. package/lib/field/Email/Email.tsx +11 -13
  25. package/lib/field/Group/Group.tsx +10 -8
  26. package/lib/field/Integer/Integer.tsx +5 -7
  27. package/lib/field/Location/Location.css +4 -0
  28. package/lib/field/Location/Location.tsx +258 -0
  29. package/lib/field/Location/config-ext.json +8 -0
  30. package/lib/field/Location/index.tsx +1 -0
  31. package/lib/field/Multiselect/utils.ts +1 -1
  32. package/lib/field/ObjectReference/ObjectReference.tsx +235 -0
  33. package/lib/field/ObjectReference/index.tsx +1 -0
  34. package/lib/field/ObjectReference/utils.ts +111 -0
  35. package/lib/field/Percentage/Percentage.tsx +3 -7
  36. package/lib/field/Phone/Phone.tsx +7 -5
  37. package/lib/field/RadioButtons/RadioButtons.tsx +47 -2
  38. package/lib/field/RichText/RichText.css +79 -0
  39. package/lib/field/RichText/RichText.tsx +3 -1
  40. package/lib/field/ScalarList/ScalarList.tsx +2 -3
  41. package/lib/field/SelectableCard/SelectableCard.tsx +175 -0
  42. package/lib/field/SelectableCard/index.tsx +1 -0
  43. package/lib/field/SelectableCard/utils.tsx +223 -0
  44. package/lib/field/SemanticLink/SemanticLink.tsx +160 -28
  45. package/lib/field/SemanticLink/utils.ts +1 -1
  46. package/lib/field/TextArea/TextArea.tsx +5 -7
  47. package/lib/field/TextContent/TextContent.tsx +1 -2
  48. package/lib/field/TextInput/TextInput.tsx +5 -7
  49. package/lib/field/Time/Time.tsx +3 -7
  50. package/lib/field/URL/URL.tsx +5 -7
  51. package/lib/field/UserReference/UserReference.tsx +2 -3
  52. package/lib/helpers/attachmentShared.ts +6 -0
  53. package/lib/helpers/common-utils.ts +3 -4
  54. package/lib/helpers/data_page.ts +0 -1
  55. package/lib/helpers/field-group-utils.ts +1 -1
  56. package/lib/helpers/formatters/Currency.ts +9 -4
  57. package/lib/helpers/formatters/CurrencyMap.ts +0 -2
  58. package/lib/helpers/object-utils.ts +10 -0
  59. package/lib/helpers/simpleTableHelpers.ts +118 -6
  60. package/lib/helpers/utils.ts +8 -1
  61. package/lib/helpers/versionHelpers.ts +0 -1
  62. package/lib/infra/ActionButtons/ActionButtons.tsx +28 -21
  63. package/lib/infra/Assignment/Assignment.tsx +37 -30
  64. package/lib/infra/AssignmentCard/AssignmentCard.tsx +2 -2
  65. package/lib/infra/Containers/FlowContainer/FlowContainer.tsx +17 -96
  66. package/lib/infra/Containers/ModalViewContainer/ListViewActionButtons/ListViewActionButtons.tsx +1 -2
  67. package/lib/infra/Containers/ModalViewContainer/ModalViewContainer.tsx +7 -6
  68. package/lib/infra/Containers/ViewContainer/ViewContainer.tsx +4 -5
  69. package/lib/infra/Containers/container-helpers.ts +47 -1
  70. package/lib/infra/DashboardFilter/DashboardFilter.tsx +3 -6
  71. package/lib/infra/DashboardFilter/filterUtils.tsx +3 -4
  72. package/lib/infra/DeferLoad/DeferLoad.tsx +2 -4
  73. package/lib/infra/ErrorBoundary/ErrorBoundary.tsx +1 -3
  74. package/lib/infra/MultiStep/MultiStep.css +48 -70
  75. package/lib/infra/MultiStep/MultiStep.tsx +27 -53
  76. package/lib/infra/NavBar/NavBar.css +1 -1
  77. package/lib/infra/NavBar/NavBar.tsx +43 -32
  78. package/lib/infra/Reference/Reference.tsx +3 -4
  79. package/lib/infra/Region/Region.tsx +1 -1
  80. package/lib/infra/RootContainer/RootContainer.tsx +2 -3
  81. package/lib/infra/Stages/Stages.tsx +3 -4
  82. package/lib/infra/View/View.tsx +4 -3
  83. package/lib/template/AdvancedSearch/AdvancedSearch.tsx +86 -0
  84. package/lib/template/AdvancedSearch/SearchGroup/persistUtils.ts +52 -0
  85. package/lib/template/AdvancedSearch/SearchGroups/SearchGroups.tsx +244 -0
  86. package/lib/template/AdvancedSearch/SearchGroups/hooks.ts +37 -0
  87. package/lib/template/AdvancedSearch/SearchGroups/index.tsx +1 -0
  88. package/lib/template/AdvancedSearch/SearchGroups/utils.ts +29 -0
  89. package/lib/template/AdvancedSearch/TemplateContext.ts +11 -0
  90. package/lib/template/AdvancedSearch/config-ext.json +9 -0
  91. package/lib/template/AdvancedSearch/index.tsx +1 -0
  92. package/lib/template/AppShell/AppShell.css +1 -1
  93. package/lib/template/AppShell/AppShell.tsx +16 -17
  94. package/lib/template/BannerPage/BannerPage.tsx +2 -2
  95. package/lib/template/CaseSummary/CaseSummary.tsx +28 -41
  96. package/lib/template/CaseView/CaseView.tsx +28 -35
  97. package/lib/template/CaseViewActionsMenu/CaseViewActionsMenu.tsx +1 -1
  98. package/lib/template/Confirmation/Confirmation.tsx +2 -3
  99. package/lib/template/DataReference/DataReference.tsx +312 -106
  100. package/lib/template/DataReference/DataReferenceAdvancedSearchContext.ts +10 -0
  101. package/lib/template/DataReference/SearchForm.tsx +149 -0
  102. package/lib/template/DataReference/utils.ts +90 -0
  103. package/lib/template/DefaultForm/DefaultForm.tsx +3 -3
  104. package/lib/template/DefaultForm/utils/index.ts +1 -3
  105. package/lib/template/DefaultPage/DefaultPage.tsx +108 -0
  106. package/lib/template/DefaultPage/index.tsx +1 -0
  107. package/lib/template/Details/Details/Details.tsx +11 -11
  108. package/lib/template/Details/DetailsSubTabs/DetailsSubTabs.tsx +2 -2
  109. package/lib/template/Details/DetailsThreeColumn/DetailsThreeColumn.tsx +11 -11
  110. package/lib/template/Details/DetailsTwoColumn/DetailsTwoColumn.tsx +11 -11
  111. package/lib/template/Details/DynamicTabs/DynamicTabs.tsx +1 -1
  112. package/lib/template/FieldGroupTemplate/FieldGroupTemplate.tsx +2 -3
  113. package/lib/template/InlineDashboard/InlineDashboard.tsx +14 -16
  114. package/lib/template/InlineDashboardPage/InlineDashboardPage.tsx +2 -2
  115. package/lib/template/ListPage/ListPage.tsx +1 -1
  116. package/lib/template/ListView/ListView.tsx +278 -198
  117. package/lib/template/ListView/hooks.ts +1 -5
  118. package/lib/template/ListView/utils.ts +38 -5
  119. package/lib/template/MultiReferenceReadOnly/MultiReferenceReadOnly.tsx +1 -1
  120. package/lib/template/NarrowWide/NarrowWide/NarrowWide.tsx +5 -5
  121. package/lib/template/NarrowWide/NarrowWideDetails/NarrowWideDetails.tsx +11 -11
  122. package/lib/template/NarrowWide/NarrowWideForm/NarrowWideForm.tsx +2 -2
  123. package/lib/template/NarrowWide/NarrowWidePage/NarrowWidePage.tsx +2 -2
  124. package/lib/template/OneColumn/OneColumn/OneColumn.tsx +7 -7
  125. package/lib/template/OneColumn/OneColumnPage/OneColumnPage.tsx +1 -1
  126. package/lib/template/OneColumn/OneColumnTab/OneColumnTab.tsx +2 -2
  127. package/lib/template/PromotedFilters/PromotedFilters.tsx +1 -2
  128. package/lib/template/SelfServiceCaseView/SelfServiceCaseView.tsx +145 -0
  129. package/lib/template/SelfServiceCaseView/index.tsx +1 -0
  130. package/lib/template/SimpleTable/SimpleTable/SimpleTable.tsx +2 -3
  131. package/lib/template/SimpleTable/SimpleTableManual/SimpleTableManual.tsx +36 -33
  132. package/lib/template/SimpleTable/SimpleTableSelect/SimpleTableSelect.tsx +1 -1
  133. package/lib/template/SingleReferenceReadOnly/SingleReferenceReadOnly.tsx +10 -2
  134. package/lib/template/SubTabs/SubTabs.tsx +2 -2
  135. package/lib/template/SubTabs/tabUtils.ts +118 -1
  136. package/lib/template/TwoColumn/TwoColumn/TwoColumn.tsx +9 -10
  137. package/lib/template/TwoColumn/TwoColumnPage/TwoColumnPage.tsx +1 -1
  138. package/lib/template/TwoColumn/TwoColumnTab/TwoColumnTab.tsx +9 -10
  139. package/lib/template/WideNarrow/WideNarrow/WideNarrow.tsx +5 -5
  140. package/lib/template/WideNarrow/WideNarrowDetails/WideNarrowDetails.tsx +11 -11
  141. package/lib/template/WideNarrow/WideNarrowForm/WideNarrowForm.tsx +2 -2
  142. package/lib/template/WideNarrow/WideNarrowPage/WideNarrowPage.tsx +2 -2
  143. package/lib/template/WssNavBar/WssNavBar.css +1 -1
  144. package/lib/template/WssNavBar/WssNavBar.tsx +6 -6
  145. package/lib/template/utils.tsx +58 -0
  146. package/lib/widget/AppAnnouncement/AppAnnouncement.tsx +1 -1
  147. package/lib/widget/Attachment/Attachment.css +6 -8
  148. package/lib/widget/Attachment/Attachment.tsx +303 -225
  149. package/lib/widget/Attachment/Attachment.types.ts +96 -0
  150. package/lib/widget/Attachment/AttachmentUtils.ts +316 -0
  151. package/lib/widget/CaseHistory/CaseHistory.tsx +5 -5
  152. package/lib/widget/FileUtility/ActionButtonsForFileUtil/ActionButtonsForFileUtil.css +0 -14
  153. package/lib/widget/FileUtility/ActionButtonsForFileUtil/ActionButtonsForFileUtil.tsx +3 -3
  154. package/lib/widget/FileUtility/FileUtility/FileUtility.css +7 -6
  155. package/lib/widget/FileUtility/FileUtility/FileUtility.tsx +29 -22
  156. package/lib/widget/Followers/Followers.tsx +2 -4
  157. package/lib/widget/QuickCreate/QuickCreate.tsx +1 -2
  158. package/lib/widget/SummaryItem/SummaryItem.css +9 -11
  159. package/lib/widget/SummaryItem/SummaryItem.tsx +2 -2
  160. package/lib/widget/SummaryList/SummaryList.tsx +1 -1
  161. package/lib/widget/ToDo/ToDo.css +1 -13
  162. package/lib/widget/ToDo/ToDo.tsx +37 -36
  163. package/package.json +1 -1
  164. package/lib/helpers/attachmentHelpers.ts +0 -76
@@ -3,7 +3,7 @@ import DoubleArrowIcon from '@mui/icons-material/DoubleArrow';
3
3
  import DoneIcon from '@mui/icons-material/Done';
4
4
  import makeStyles from '@mui/styles/makeStyles';
5
5
 
6
- import { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
6
+ import type { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
7
7
 
8
8
  interface StagesProps extends PConnProps {
9
9
  // If any, enter additional props that only exist on this component
@@ -57,14 +57,13 @@ export default function Stages(props: StagesProps) {
57
57
 
58
58
  const { getPConnect, stages } = props;
59
59
  const pConn = getPConnect();
60
- const key = `${pConn.getCaseInfo().getClassName()}!CASE!${pConn.getCaseInfo().getName()}`.toUpperCase();
61
-
60
+ const localizationService = pConn.getLocalizationService();
62
61
  const filteredStages = getFilteredStages(stages);
63
62
  const currentStageID = pConn.getValue(PCore.getConstants().CASE_INFO.STAGEID, ''); // 2nd arg empty string until typedef allows optional
64
63
  const stagesObj = filteredStages.map((stage, index, arr) => {
65
64
  const theID = stage.ID || stage.id;
66
65
  return {
67
- name: PCore.getLocaleUtils().getLocaleValue(stage.name, undefined, key),
66
+ name: localizationService.getLocalizedText(stage.name),
68
67
  id: theID,
69
68
  complete: stage.visited_status === 'completed',
70
69
  current: theID === currentStageID,
@@ -1,8 +1,8 @@
1
- import { PropsWithChildren, useEffect } from 'react';
1
+ import { type PropsWithChildren, useEffect } from 'react';
2
2
 
3
3
  import { getComponentFromMap } from '@pega/react-sdk-components/lib/bridge/helpers/sdk_component_map';
4
4
  import { getAllFields } from '@pega/react-sdk-components/lib/components/helpers/template-utils';
5
- import { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
5
+ import type { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
6
6
 
7
7
  // Need to import any templates that we might render
8
8
 
@@ -38,7 +38,8 @@ const NO_HEADER_TEMPLATES = [
38
38
  'WideNarrowDetails',
39
39
  'Confirmation',
40
40
  'DynamicTabs',
41
- 'DetailsSubTabs'
41
+ 'DetailsSubTabs',
42
+ 'ListView'
42
43
  ];
43
44
 
44
45
  export default function View(props: PropsWithChildren<ViewProps>) {
@@ -0,0 +1,86 @@
1
+ import { useContext, useState } from 'react';
2
+
3
+ import { getComponentFromMap } from '@pega/react-sdk-components/lib/bridge/helpers/sdk_component_map';
4
+ import DataReferenceAdvancedSearchContext from '@pega/react-sdk-components/lib/components/template/DataReference/DataReferenceAdvancedSearchContext';
5
+ import { getFirstChildConfig } from '@pega/react-sdk-components/lib/components/template/DataReference/utils';
6
+
7
+ export default function AdvancedSearch(props) {
8
+ const { getPConnect, targetObjectClass, localeReference } = props;
9
+ const SearchGroups = getComponentFromMap('SearchGroups');
10
+ const { dataReferenceConfigToChild, isCreateNewReferenceEnabled, disableStartingFieldsForReference, pyID, searchSelectCacheKey } = useContext(
11
+ DataReferenceAdvancedSearchContext
12
+ ) as any;
13
+
14
+ const { selectionMode, value: singleSelectFieldValue, readonlyContextList: multiSelectField } = dataReferenceConfigToChild;
15
+
16
+ let isSelectionExist = false;
17
+ const { MULTI } = PCore.getConstants().LIST_SELECTION_MODE;
18
+
19
+ if (selectionMode === MULTI) {
20
+ isSelectionExist = getPConnect().getValue(multiSelectField)?.length || false;
21
+ } else {
22
+ isSelectionExist = getPConnect().getValue(singleSelectFieldValue) || false;
23
+ }
24
+
25
+ const [showRecords, setShowRecords] = useState(isSelectionExist);
26
+
27
+ const pConn = getPConnect();
28
+ const rawViewMetadata = pConn.getRawMetadata();
29
+
30
+ const searchFieldsSet = new Set();
31
+ const searchFields: any = [];
32
+ rawViewMetadata.config.searchGroups.forEach(group => {
33
+ group.children.forEach(child => {
34
+ if (!searchFieldsSet.has(child.config.value) && !child.config.validator) {
35
+ searchFields.push(child);
36
+ searchFieldsSet.add(child.config.value);
37
+ }
38
+ });
39
+ });
40
+
41
+ const firstChildPConnect = getPConnect().getChildren()[0].getPConnect;
42
+ const [firstChildMeta] = rawViewMetadata.children;
43
+
44
+ const localizedVal = PCore.getLocaleUtils().getLocaleValue;
45
+ const cache = PCore.getNavigationUtils().getComponentCache(searchSelectCacheKey) ?? {};
46
+
47
+ const editableFieldComp = firstChildPConnect().createComponent({
48
+ type: firstChildMeta.type,
49
+ config: {
50
+ ...getFirstChildConfig({
51
+ firstChildMeta,
52
+ getPConnect,
53
+ rawViewMetadata,
54
+ contextClass: targetObjectClass,
55
+ dataReferenceConfigToChild,
56
+ isCreateNewReferenceEnabled,
57
+ disableStartingFieldsForReference,
58
+ pyID
59
+ }),
60
+ searchFields,
61
+ showRecords,
62
+ label: localizedVal('Search results', 'DataReference'),
63
+ searchSelectCacheKey,
64
+ cache
65
+ }
66
+ });
67
+
68
+ const { selectionList, dataRelationshipContext } = editableFieldComp.props.getPConnect().getConfigProps();
69
+ const editableField = selectionMode === MULTI ? selectionList.substring(1) : dataRelationshipContext;
70
+
71
+ const searchGroupsProps = {
72
+ getPConnect,
73
+ editableField,
74
+ localeReference,
75
+ setShowRecords,
76
+ searchSelectCacheKey,
77
+ cache
78
+ };
79
+
80
+ return (
81
+ <>
82
+ <SearchGroups {...searchGroupsProps} />
83
+ {editableFieldComp}
84
+ </>
85
+ );
86
+ }
@@ -0,0 +1,52 @@
1
+ import { Utils } from '@pega/react-sdk-components/lib/components/helpers/utils';
2
+
3
+ const SKIP_CACHE_KEY = '';
4
+
5
+ const getComponentStateKey = (getPConnect, propertyName: string) => {
6
+ const pConnect = getPConnect();
7
+ const caseID = `.${Utils.getMappedKey('pyID')}`; // Enhance this later when use-case arrives for data objects using S&S.
8
+ const resolvedCaseID = pConnect.getValue(caseID);
9
+
10
+ if (!resolvedCaseID) {
11
+ return SKIP_CACHE_KEY;
12
+ }
13
+
14
+ return `Search-${resolvedCaseID}-${pConnect.getPageReference()}-${propertyName}-${pConnect.getCurrentView()}`;
15
+ };
16
+
17
+ const getComponentStateOptions = getPConnect => {
18
+ return { clearOnCancelForContext: getPConnect().getContextName() };
19
+ };
20
+
21
+ interface SearchCategory {
22
+ // tabId of search category selected
23
+ selectedCategory: string;
24
+ }
25
+
26
+ interface SearchGroup {
27
+ // searchFields can be any object based on what fields are authored.
28
+ searchFields: unknown;
29
+ activeGroupId: string;
30
+ }
31
+
32
+ const setComponentCache = ({
33
+ cacheKey,
34
+ state,
35
+ options
36
+ }: {
37
+ cacheKey: string;
38
+ state: SearchCategory | SearchGroup;
39
+ options: ReturnType<typeof getComponentStateOptions>;
40
+ }) => {
41
+ if (cacheKey !== SKIP_CACHE_KEY) {
42
+ (PCore.getNavigationUtils() as any).setComponentCache(cacheKey, state, options);
43
+ }
44
+ };
45
+
46
+ const componentCachePersistUtils = {
47
+ getComponentStateKey,
48
+ getComponentStateOptions,
49
+ setComponentCache
50
+ };
51
+
52
+ export default componentCachePersistUtils;
@@ -0,0 +1,244 @@
1
+ import React, { createElement, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { Button, Grid2, Select, MenuItem, Box } from '@mui/material';
3
+
4
+ import createPConnectComponent from '@pega/react-sdk-components/lib/bridge/react_pconnect';
5
+ import TemplateContext from '@pega/react-sdk-components/lib/components/template/AdvancedSearch/TemplateContext';
6
+ import componentCachePersistUtils from '@pega/react-sdk-components/lib/components/template/AdvancedSearch/SearchGroup/persistUtils';
7
+
8
+ import { getCacheInfo, isValidInput } from './utils';
9
+ import { useCacheWhenListViewReady } from './hooks';
10
+
11
+ export const initializeSearchFields = (searchFields, getPConnect, referenceListClassID, searchFieldRestoreValues = {}) => {
12
+ const filtersProperties = {};
13
+ searchFields.forEach(field => {
14
+ let val = '';
15
+ const { value, defaultValue = '' } = field.config;
16
+ const propPath = PCore.getAnnotationUtils().getPropertyName(value);
17
+
18
+ if (searchFieldRestoreValues[propPath]) {
19
+ val = searchFieldRestoreValues[propPath];
20
+ } else if (PCore.getAnnotationUtils().isProperty(defaultValue)) {
21
+ val = getPConnect().getValue(defaultValue.split(' ')[1]);
22
+ } else if (defaultValue.startsWith('@L')) {
23
+ val = defaultValue.split(' ')[1];
24
+ } else {
25
+ val = defaultValue;
26
+ }
27
+
28
+ filtersProperties[propPath] = val;
29
+
30
+ const valueSplit = value.split('@P ')[1]?.split('.').filter(Boolean) ?? [];
31
+ valueSplit.pop();
32
+
33
+ if (valueSplit.length) {
34
+ let path = '';
35
+ let currentClassID = referenceListClassID;
36
+ valueSplit.forEach(item => {
37
+ path = path.length ? `${path}.${item}` : item;
38
+ currentClassID = (PCore.getMetadataUtils().getPropertyMetadata(item, currentClassID) as any).pageClass;
39
+ if (currentClassID) {
40
+ filtersProperties[`${path}.classID`] = currentClassID;
41
+ }
42
+ });
43
+ }
44
+ });
45
+ return filtersProperties;
46
+ };
47
+
48
+ const flattenObj = obj => {
49
+ const result = {};
50
+ Object.keys(obj).forEach(key => {
51
+ if (!['context_data', 'pageInstructions'].includes(key)) {
52
+ if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
53
+ const temp = flattenObj(obj[key]);
54
+ Object.keys(temp).forEach(nestedKey => {
55
+ result[`${key}.${nestedKey}`] = temp[nestedKey];
56
+ });
57
+ } else {
58
+ result[key] = obj[key];
59
+ }
60
+ }
61
+ });
62
+ return result;
63
+ };
64
+
65
+ export default function SearchGroups(props) {
66
+ const localizedVal = PCore.getLocaleUtils().getLocaleValue;
67
+ const { getPConnect, editableField, localeReference, setShowRecords, searchSelectCacheKey, cache } = props;
68
+ const referenceFieldName = editableField.replaceAll('.', '_');
69
+
70
+ const state: any = useRef({ searchFields: {}, activeGroupId: '' }).current;
71
+ const options = componentCachePersistUtils.getComponentStateOptions(getPConnect);
72
+
73
+ const { searchGroups: groups, referenceList } = getPConnect().getConfigProps();
74
+ const { useCache, initialActiveGroupId } = getCacheInfo(cache, groups);
75
+ const [activeGroupId, setActiveGroupId] = useState(initialActiveGroupId);
76
+ const [transientItemID, setTransientItemID] = useState<any>(null);
77
+ const [previousFormValues, setPreviousFormValues] = useState<any>(null);
78
+ const viewName = getPConnect().getCurrentView();
79
+
80
+ const rawGroupsConfig = getPConnect().getRawConfigProps().searchGroups;
81
+ const activeGroupIndex = groups.findIndex(group => group.config.id === activeGroupId);
82
+ const { children: searchFieldsChildren = [] } = activeGroupIndex !== -1 ? rawGroupsConfig[activeGroupIndex] : {};
83
+ const searchFields = searchFieldsChildren.map(field => ({
84
+ ...field,
85
+ config: { ...field.config, isSearchField: true }
86
+ }));
87
+
88
+ const searchByRef = useRef(null);
89
+ const searchFieldsRef = useRef(null);
90
+ const isValidatorField = searchFields.some(field => field.config.validator);
91
+ const { classID: referenceListClassID } = PCore.getMetadataUtils().getDataPageMetadata(referenceList) as any;
92
+
93
+ const initialSearchFields = useMemo(
94
+ () =>
95
+ initializeSearchFields(
96
+ searchFields,
97
+ getPConnect,
98
+ referenceListClassID,
99
+ useCache && cache.activeGroupId === activeGroupId ? cache.searchFields : {}
100
+ ),
101
+ [activeGroupId, getPConnect, cache.searchFields]
102
+ );
103
+
104
+ useEffect(() => {
105
+ if (transientItemID) {
106
+ const filtersWithClassID = {
107
+ ...initialSearchFields,
108
+ classID: referenceListClassID
109
+ };
110
+ // @ts-ignore
111
+ PCore.getContainerUtils().replaceTransientData({ transientItemID, data: filtersWithClassID });
112
+ }
113
+ }, [activeGroupId]);
114
+
115
+ useEffect(() => {
116
+ const filtersWithClassID = {
117
+ ...initialSearchFields,
118
+ classID: referenceListClassID
119
+ };
120
+
121
+ const transientId = getPConnect()
122
+ .getContainerManager()
123
+ .addTransientItem({ id: `${referenceFieldName}-${viewName}`, data: filtersWithClassID });
124
+ setTransientItemID(transientId);
125
+ }, []);
126
+
127
+ const getFilterData = useCallback(() => {
128
+ // @ts-ignore
129
+ let changes = PCore.getFormUtils().getSubmitData(transientItemID, {
130
+ isTransientContext: true,
131
+ includeDisabledFields: true
132
+ });
133
+
134
+ if (Object.keys(cache.searchFields ?? {}).length > 0 && Object.keys(changes).length === 1) {
135
+ changes = cache.searchFields;
136
+ }
137
+
138
+ const formValues = flattenObj(changes);
139
+
140
+ if (!PCore.isDeepEqual(previousFormValues, formValues) && PCore.getFormUtils().isFormValid(transientItemID) && isValidInput(formValues)) {
141
+ if (isValidatorField) {
142
+ // @ts-ignore
143
+ PCore.getMessageManager().clearContextMessages({ context: transientItemID });
144
+ }
145
+ setPreviousFormValues(formValues);
146
+ setShowRecords(true);
147
+ PCore.getPubSubUtils().publish(PCore.getEvents().getTransientEvent().UPDATE_PROMOTED_FILTERS, {
148
+ payload: formValues,
149
+ showRecords: true,
150
+ viewName
151
+ });
152
+ }
153
+
154
+ state.activeGroupId = activeGroupId;
155
+ state.searchFields = changes;
156
+ state.selectedCategory = viewName;
157
+
158
+ componentCachePersistUtils.setComponentCache({ cacheKey: searchSelectCacheKey, state, options });
159
+ }, [transientItemID, setShowRecords, viewName, activeGroupId, previousFormValues]);
160
+
161
+ const resetFilterData = useCallback(() => {
162
+ // @ts-ignore
163
+ PCore.getNavigationUtils().resetComponentCache(searchSelectCacheKey);
164
+ const resetPayload = {
165
+ transientItemID,
166
+ data: initializeSearchFields(searchFields, getPConnect, referenceListClassID),
167
+ options: { reset: true }
168
+ };
169
+ // @ts-ignore
170
+ PCore.getContainerUtils().updateTransientData(resetPayload);
171
+ }, [transientItemID, initialSearchFields]);
172
+
173
+ useCacheWhenListViewReady(cache, viewName, useCache, getFilterData, searchSelectCacheKey);
174
+
175
+ const searchDropdown = groups.length > 1 && (
176
+ <Grid2 container spacing={2}>
177
+ <Select value={activeGroupId} onChange={e => setActiveGroupId(e.target.value)} ref={searchByRef} fullWidth>
178
+ {groups.map(group => (
179
+ <MenuItem key={group.config.id} value={group.config.id}>
180
+ {group.config.label}
181
+ </MenuItem>
182
+ ))}
183
+ </Select>
184
+ </Grid2>
185
+ );
186
+
187
+ const actionButtons = (
188
+ <Box display='flex' gap={2}>
189
+ <Button variant='outlined' onClick={resetFilterData}>
190
+ {localizedVal('Reset', 'SimpleTable')}
191
+ </Button>
192
+ <Button variant='contained' onClick={getFilterData}>
193
+ {localizedVal('Search', 'SimpleTable')}
194
+ </Button>
195
+ </Box>
196
+ );
197
+
198
+ const searchFieldsViewConfig = {
199
+ name: 'SearchFields',
200
+ type: 'View',
201
+ config: {
202
+ template: 'DefaultForm',
203
+ NumCols: '3',
204
+ contextName: transientItemID,
205
+ readOnly: false,
206
+ context: transientItemID,
207
+ localeReference
208
+ },
209
+ children: [
210
+ {
211
+ name: 'Fields',
212
+ type: 'Region',
213
+ children: searchFields
214
+ }
215
+ ]
216
+ };
217
+
218
+ const searchFieldsC11nEnv = PCore.createPConnect({
219
+ meta: searchFieldsViewConfig,
220
+ options: {
221
+ hasForm: true,
222
+ contextName: transientItemID
223
+ }
224
+ });
225
+
226
+ const templateContext = useContext(TemplateContext);
227
+ const templateContextValue = useMemo(() => ({ ...templateContext, outerColumnCount: undefined }), []);
228
+
229
+ const searchFieldsViewComp = transientItemID ? (
230
+ <TemplateContext.Provider value={templateContextValue}>
231
+ <div ref={searchFieldsRef}>{createElement(createPConnectComponent(), { ...searchFieldsC11nEnv })}</div>
232
+ </TemplateContext.Provider>
233
+ ) : null;
234
+
235
+ const childrenToRender = [searchDropdown, searchFieldsViewComp, actionButtons];
236
+
237
+ return (
238
+ <Box display='flex' flexDirection='column' gap={2}>
239
+ {childrenToRender.map((child, index) => (
240
+ <React.Fragment key={index}>{child}</React.Fragment>
241
+ ))}
242
+ </Box>
243
+ );
244
+ }
@@ -0,0 +1,37 @@
1
+ import { useEffect } from 'react';
2
+
3
+ const listViewConstants = {
4
+ EVENTS: {
5
+ LIST_VIEW_READY: 'LIST_VIEW_READY'
6
+ }
7
+ };
8
+ /**
9
+ * This hook registers a callback for the whenever list view component is ready
10
+ * then makes a call to get the data using the search fields pre-filled with cache data.
11
+ */
12
+
13
+ export function useCacheWhenListViewReady(
14
+ cache: { searchFields: unknown },
15
+ viewName: string,
16
+ useCache: boolean,
17
+ getFilterData: (params: { isCalledFromCache: boolean }) => void,
18
+ searchSelectCacheKey: string
19
+ ) {
20
+ useEffect(() => {
21
+ if (Object.keys(cache.searchFields ?? {}).length > 0) {
22
+ PCore.getPubSubUtils().subscribe(
23
+ listViewConstants.EVENTS.LIST_VIEW_READY,
24
+ ({ viewName: viewNameFromListView }: { viewName: string }) => {
25
+ if (viewNameFromListView === viewName && useCache) {
26
+ getFilterData({ isCalledFromCache: true });
27
+ }
28
+ },
29
+ `${searchSelectCacheKey}-listview-ready`
30
+ );
31
+ }
32
+
33
+ return () => {
34
+ PCore.getPubSubUtils().unsubscribe(listViewConstants.EVENTS.LIST_VIEW_READY, `${searchSelectCacheKey}-listview-ready`);
35
+ };
36
+ }, []);
37
+ }
@@ -0,0 +1 @@
1
+ export { default } from './SearchGroups';
@@ -0,0 +1,29 @@
1
+ function isEmpty(value: any): boolean {
2
+ return (
3
+ // null or undefined
4
+ value === null ||
5
+ value === undefined ||
6
+ ((Array.isArray(value) || typeof value === 'string') && value.length === 0) ||
7
+ // is an Object and has no keys
8
+ (value.constructor === Object && Object.keys(value).length === 0)
9
+ );
10
+ }
11
+
12
+ export function getCacheInfo(
13
+ cache: { selectedCategory: string; activeGroupId: string; searchFields: unknown },
14
+ groups: { config: { id: string } }[]
15
+ ) {
16
+ let initialActiveGroupId = groups.length ? groups[0].config.id : '';
17
+
18
+ let useCache = false;
19
+ if (cache.activeGroupId && groups?.find(group => group.config.id === cache.activeGroupId)) {
20
+ initialActiveGroupId = cache.activeGroupId;
21
+ useCache = true;
22
+ }
23
+
24
+ return { useCache, initialActiveGroupId };
25
+ }
26
+
27
+ export function isValidInput(input: { [s: string]: unknown }) {
28
+ return Object.values(input).some(value => !isEmpty(value));
29
+ }
@@ -0,0 +1,11 @@
1
+ import { createContext } from 'react';
2
+
3
+ const TemplateContext = createContext({
4
+ depth: 0,
5
+ columnCount: 1,
6
+ outerColumnCount: undefined,
7
+ templateOverrideMode: undefined,
8
+ inheritParentLayout: undefined,
9
+ lastContainerItem: undefined
10
+ });
11
+ export default TemplateContext;
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "AdvancedSearch",
3
+ "label": "Advanced search",
4
+ "type": "Template",
5
+ "icon": "AdvancedSearch.svg",
6
+ "subtype": "SEARCH",
7
+ "hideTemplateEdit": true,
8
+ "properties": []
9
+ }
@@ -0,0 +1 @@
1
+ export { default } from './AdvancedSearch';
@@ -22,7 +22,7 @@
22
22
  align-items: center;
23
23
  height: 100%;
24
24
  width: 100%;
25
- background-color: whitesmoke;
25
+ background-color: 'var(--app-background-color)';
26
26
  position: fixed;
27
27
  z-index: 999;
28
28
  top: 0rem;
@@ -1,11 +1,11 @@
1
- import { PropsWithChildren, useEffect, useState } from 'react';
1
+ import { type PropsWithChildren, useEffect, useState } from 'react';
2
2
  import makeStyles from '@mui/styles/makeStyles';
3
3
  import Avatar from '@mui/material/Avatar';
4
4
 
5
5
  import { Utils } from '@pega/react-sdk-components/lib/components/helpers/utils';
6
6
  import { NavContext } from '@pega/react-sdk-components/lib/components/helpers/reactContextHelpers';
7
7
  import { getComponentFromMap } from '@pega/react-sdk-components/lib/bridge/helpers/sdk_component_map';
8
- import { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
8
+ import type { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
9
9
 
10
10
  import './AppShell.css';
11
11
 
@@ -29,9 +29,7 @@ interface AppShellProps extends PConnProps {
29
29
  }
30
30
 
31
31
  const useStyles = makeStyles(theme => ({
32
- root: {
33
- display: 'flex'
34
- },
32
+ root: {},
35
33
  content: {
36
34
  flexGrow: 1,
37
35
  height: '100vh',
@@ -83,7 +81,7 @@ export default function AppShell(props: PropsWithChildren<AppShellProps>) {
83
81
  const classes = useStyles();
84
82
  const actionsAPI = pConn.getActionsApi();
85
83
  const localeReference = pConn.getValue('.pyLocaleReference', ''); // 2nd arg empty string until typedef marked correctly
86
- const [imageBlobUrl, setImageBlobUrl] = useState<string | null>(null);
84
+ const [imageBlobUrl, setImageBlobUrl] = useState<string | Blob | null>(null);
87
85
  // useState for appName and mapChildren - note these are ONLY updated once (on component mount!)
88
86
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
89
87
  const [appName, setAppName] = useState('');
@@ -114,10 +112,15 @@ export default function AppShell(props: PropsWithChildren<AppShellProps>) {
114
112
  });
115
113
 
116
114
  setMapChildren(tempMap);
115
+
116
+ /* TODO: We're setting the `pyPortalTemplate` for now, this would be handled by the CoreJS in the future releases */
117
+ if (portalTemplate === 'wss') {
118
+ PCore.getEnvironmentInfo().setEnvironmentInfo({ ...PCore.getEnvironmentInfo().environmentInfoObject, pyPortalTemplate: 'wss' } as any);
119
+ }
117
120
  }, []);
118
121
 
119
122
  useEffect(() => {
120
- // @ts-ignore
123
+ // @ts-expect-error
121
124
  const caseTypesAvailableToCreateDP = PCore.getEnvironmentInfo().environmentInfoObject?.pxApplication?.pyCaseTypesAvailableToCreateDP;
122
125
  if (caseTypesAvailableToCreateDP) {
123
126
  const portalID = pConn.getValue('.pyOwner');
@@ -135,8 +138,8 @@ export default function AppShell(props: PropsWithChildren<AppShellProps>) {
135
138
  }
136
139
  }, []);
137
140
 
138
- const [iconURL, setIconURL] = useState('');
139
- const [fullIconURL, setFullIconURL] = useState('');
141
+ const [iconURL, setIconURL] = useState<string | Blob>('');
142
+ const [fullIconURL, setFullIconURL] = useState<string | Blob>('');
140
143
  useEffect(() => {
141
144
  // using the default icon then fetch it from the static folder (not auth involved)
142
145
  if (
@@ -152,14 +155,12 @@ export default function AppShell(props: PropsWithChildren<AppShellProps>) {
152
155
  // not using default icon to fetch it using the way which uses authentication
153
156
  else {
154
157
  PCore.getAssetLoader()
155
- .getSvcImage(portalLogo)
156
- .then(blob => window.URL.createObjectURL(blob))
158
+ .getSvcImageUrl(portalLogo)
157
159
  .then(data => {
158
160
  setIconURL(data);
159
161
  setFullIconURL(data);
160
162
  })
161
163
  .catch(() => {
162
- // eslint-disable-next-line no-console
163
164
  console.error(`${localizedVal('Unable to load the image for the portal logo/icon with the insName', 'AppShell')}:${portalLogo}`);
164
165
  });
165
166
  }
@@ -168,8 +169,7 @@ export default function AppShell(props: PropsWithChildren<AppShellProps>) {
168
169
  useEffect(() => {
169
170
  if (imageKey && portalTemplate === 'wss') {
170
171
  PCore.getAssetLoader()
171
- .getSvcImage(imageKey)
172
- .then(blob => window.URL.createObjectURL(blob))
172
+ .getSvcImageUrl(imageKey)
173
173
  .then(imagePath => setImageBlobUrl(imagePath));
174
174
  }
175
175
  }, []);
@@ -213,7 +213,7 @@ export default function AppShell(props: PropsWithChildren<AppShellProps>) {
213
213
 
214
214
  if (portalTemplate === 'wss') {
215
215
  return (
216
- <div id='AppShell'>
216
+ <div id='AppShell' className={classes.root}>
217
217
  <WssNavBar
218
218
  portalName={portalName}
219
219
  imageSrc={iconURL}
@@ -239,9 +239,8 @@ export default function AppShell(props: PropsWithChildren<AppShellProps>) {
239
239
  }
240
240
 
241
241
  return (
242
- // eslint-disable-next-line react/jsx-no-constructed-context-values
243
242
  <NavContext.Provider value={{ open, setOpen }}>
244
- <div id='AppShell' className={classes.root}>
243
+ <div id='AppShell' className={classes.root} style={{ display: 'flex' }}>
245
244
  <NavBar
246
245
  getPConnect={getPConnect}
247
246
  pConn={getPConnect()}
@@ -1,7 +1,7 @@
1
- import { Children, PropsWithChildren, useMemo } from 'react';
1
+ import { Children, type PropsWithChildren, useMemo } from 'react';
2
2
 
3
3
  import { getComponentFromMap } from '@pega/react-sdk-components/lib/bridge/helpers/sdk_component_map';
4
- import { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
4
+ import type { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
5
5
 
6
6
  interface BannerPageProps extends PConnProps {
7
7
  // If any, enter additional props that only exist on this component