@pega/react-sdk-overrides 0.24.3 → 0.25.1

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 (118) hide show
  1. package/lib/designSystemExtension/AlertBanner/AlertBanner.tsx +1 -1
  2. package/lib/designSystemExtension/Banner/Banner.tsx +1 -1
  3. package/lib/designSystemExtension/CaseSummaryFields/CaseSummaryFields.css +0 -1
  4. package/lib/designSystemExtension/CaseSummaryFields/CaseSummaryFields.tsx +11 -2
  5. package/lib/designSystemExtension/DetailsFields/DetailsFields.tsx +4 -4
  6. package/lib/designSystemExtension/FieldGroup/FieldGroup.tsx +4 -4
  7. package/lib/designSystemExtension/FieldGroupList/FieldGroupList.tsx +4 -4
  8. package/lib/designSystemExtension/FieldValueList/FieldValueList.tsx +6 -6
  9. package/lib/designSystemExtension/Operator/Operator.tsx +6 -5
  10. package/lib/designSystemExtension/Pulse/Pulse.tsx +2 -2
  11. package/lib/designSystemExtension/RichTextEditor/RichTextEditor.tsx +3 -2
  12. package/lib/designSystemExtension/WssQuickCreate/WssQuickCreate.tsx +1 -1
  13. package/lib/field/AutoComplete/AutoComplete.tsx +4 -4
  14. package/lib/field/CancelAlert/CancelAlert.tsx +4 -7
  15. package/lib/field/Checkbox/Checkbox.tsx +4 -4
  16. package/lib/field/Currency/Currency.tsx +10 -7
  17. package/lib/field/Date/Date.tsx +27 -42
  18. package/lib/field/DateTime/DateTime.tsx +39 -36
  19. package/lib/field/Decimal/Decimal.tsx +9 -4
  20. package/lib/field/Dropdown/Dropdown.tsx +29 -22
  21. package/lib/field/Email/Email.tsx +29 -8
  22. package/lib/field/Group/Group.tsx +2 -2
  23. package/lib/field/Integer/Integer.tsx +22 -8
  24. package/lib/field/Multiselect/Multiselect.tsx +8 -14
  25. package/lib/field/Multiselect/utils.ts +1 -1
  26. package/lib/field/Percentage/Percentage.tsx +8 -4
  27. package/lib/field/Phone/Phone.tsx +22 -12
  28. package/lib/field/Phone/config-ext.json +8 -0
  29. package/lib/field/RadioButtons/RadioButtons.tsx +3 -6
  30. package/lib/field/RichText/RichText.tsx +1 -1
  31. package/lib/field/RichText/config-ext.json +10 -0
  32. package/lib/field/ScalarList/ScalarList.tsx +3 -4
  33. package/lib/field/SemanticLink/SemanticLink.tsx +4 -4
  34. package/lib/field/TextArea/TextArea.tsx +26 -8
  35. package/lib/field/TextContent/TextContent.tsx +1 -1
  36. package/lib/field/TextInput/TextInput.tsx +2 -2
  37. package/lib/field/Time/Time.tsx +28 -21
  38. package/lib/field/URL/URL.tsx +26 -7
  39. package/lib/field/UserReference/UserReference.tsx +3 -5
  40. package/lib/helpers/common-utils.ts +24 -1
  41. package/lib/helpers/field-group-utils.ts +2 -2
  42. package/lib/helpers/formatters/Currency.ts +11 -16
  43. package/lib/helpers/formatters/common.ts +2 -1
  44. package/lib/helpers/formatters/index.ts +2 -4
  45. package/lib/helpers/simpleTableHelpers.ts +1 -1
  46. package/lib/infra/ActionButtons/ActionButtons.tsx +3 -3
  47. package/lib/infra/Assignment/Assignment.tsx +38 -12
  48. package/lib/infra/Containers/FlowContainer/FlowContainer.tsx +16 -28
  49. package/lib/infra/Containers/FlowContainer/helpers.ts +1 -5
  50. package/lib/infra/Containers/ModalViewContainer/ListViewActionButtons/ListViewActionButtons.tsx +9 -4
  51. package/lib/infra/Containers/ModalViewContainer/ModalViewContainer.tsx +8 -8
  52. package/lib/infra/Containers/SimpleView/helper.ts +1 -1
  53. package/lib/infra/Containers/ViewContainer/ViewContainer.tsx +1 -1
  54. package/lib/infra/DashboardFilter/DashboardFilter.tsx +4 -6
  55. package/lib/infra/DashboardFilter/filterUtils.tsx +3 -4
  56. package/lib/infra/DeferLoad/DeferLoad.tsx +8 -8
  57. package/lib/infra/MultiStep/MultiStep.tsx +15 -14
  58. package/lib/infra/NavBar/NavBar.css +1 -0
  59. package/lib/infra/NavBar/NavBar.tsx +25 -17
  60. package/lib/infra/RootContainer/RootContainer.tsx +5 -6
  61. package/lib/infra/Stages/Stages.tsx +4 -4
  62. package/lib/infra/VerticalTabs/LeftAlignVerticalTabs/LeftAlignVerticalTabs.tsx +4 -3
  63. package/lib/infra/VerticalTabs/VerticalTabs/VerticalTabs.tsx +2 -2
  64. package/lib/infra/View/View.tsx +37 -3
  65. package/lib/template/AdvancedSearch/AdvancedSearch.tsx +87 -0
  66. package/lib/template/AdvancedSearch/SearchGroup/persistUtils.ts +58 -0
  67. package/lib/template/AdvancedSearch/SearchGroups/SearchGroups.tsx +245 -0
  68. package/lib/template/AdvancedSearch/SearchGroups/hooks.ts +37 -0
  69. package/lib/template/AdvancedSearch/SearchGroups/index.tsx +1 -0
  70. package/lib/template/AdvancedSearch/SearchGroups/utils.ts +29 -0
  71. package/lib/template/AdvancedSearch/TemplateContext.ts +11 -0
  72. package/lib/template/AdvancedSearch/config-ext.json +9 -0
  73. package/lib/template/AdvancedSearch/index.tsx +1 -0
  74. package/lib/template/AppShell/AppShell.tsx +60 -10
  75. package/lib/template/BannerPage/config-ext.json +9 -0
  76. package/lib/template/CaseView/CaseView.tsx +10 -9
  77. package/lib/template/CaseViewActionsMenu/CaseViewActionsMenu.tsx +7 -7
  78. package/lib/template/Confirmation/Confirmation.tsx +3 -2
  79. package/lib/template/DataReference/DataReference.tsx +317 -107
  80. package/lib/template/DataReference/DataReferenceAdvancedSearchContext.js +10 -0
  81. package/lib/template/DataReference/SearchForm.tsx +148 -0
  82. package/lib/template/DataReference/utils.js +90 -0
  83. package/lib/template/DefaultForm/utils/index.ts +1 -3
  84. package/lib/template/Details/Details/Details.tsx +2 -2
  85. package/lib/template/Details/DetailsSubTabs/DetailsSubTabs.tsx +3 -3
  86. package/lib/template/Details/DetailsThreeColumn/DetailsThreeColumn.tsx +2 -2
  87. package/lib/template/Details/DetailsTwoColumn/DetailsTwoColumn.tsx +2 -2
  88. package/lib/template/Details/DynamicTabs/DynamicTabs.tsx +4 -4
  89. package/lib/template/FieldGroupTemplate/FieldGroupTemplate.tsx +10 -5
  90. package/lib/template/InlineDashboard/InlineDashboard.tsx +2 -2
  91. package/lib/template/InlineDashboardPage/config-ext.json +9 -0
  92. package/lib/template/ListView/ListView.tsx +216 -123
  93. package/lib/template/ListView/utils.ts +38 -6
  94. package/lib/template/NarrowWide/NarrowWideDetails/NarrowWideDetails.tsx +2 -2
  95. package/lib/template/OneColumn/OneColumn/OneColumn.tsx +2 -2
  96. package/lib/template/PromotedFilters/PromotedFilters.tsx +1 -2
  97. package/lib/template/SimpleTable/SimpleTable/SimpleTable.tsx +0 -2
  98. package/lib/template/SimpleTable/SimpleTableManual/SimpleTableManual.tsx +110 -86
  99. package/lib/template/SimpleTable/SimpleTableSelect/SimpleTableSelect.tsx +2 -4
  100. package/lib/template/SubTabs/SubTabs.tsx +2 -2
  101. package/lib/template/SubTabs/tabUtils.ts +118 -1
  102. package/lib/template/TwoColumn/TwoColumn/TwoColumn.tsx +2 -2
  103. package/lib/template/TwoColumn/TwoColumnTab/TwoColumnTab.tsx +2 -2
  104. package/lib/template/WideNarrow/WideNarrowDetails/WideNarrowDetails.tsx +2 -2
  105. package/lib/template/WssNavBar/WssNavBar.tsx +9 -9
  106. package/lib/widget/AppAnnouncement/AppAnnouncement.tsx +2 -2
  107. package/lib/widget/Attachment/Attachment.css +1 -0
  108. package/lib/widget/Attachment/Attachment.tsx +7 -9
  109. package/lib/widget/CaseHistory/CaseHistory.tsx +12 -10
  110. package/lib/widget/FileUtility/ActionButtonsForFileUtil/ActionButtonsForFileUtil.tsx +1 -1
  111. package/lib/widget/FileUtility/FileUtility/FileUtility.tsx +5 -4
  112. package/lib/widget/Followers/Followers.tsx +2 -2
  113. package/lib/widget/QuickCreate/QuickCreate.tsx +0 -1
  114. package/lib/widget/QuickCreate/config-ext.json +9 -0
  115. package/lib/widget/SummaryItem/SummaryItem.tsx +4 -3
  116. package/lib/widget/ToDo/ToDo.tsx +92 -22
  117. package/package.json +1 -1
  118. /package/lib/infra/Containers/{helpers.ts → container-helpers.ts} +0 -0
@@ -1,4 +1,4 @@
1
- import { PropsWithChildren } from 'react';
1
+ import { 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';
@@ -18,6 +18,7 @@ interface ViewProps extends PConnProps {
18
18
  visibility?: boolean;
19
19
  name?: string;
20
20
  bInForm?: boolean;
21
+ type?: any;
21
22
  }
22
23
 
23
24
  //
@@ -36,12 +37,14 @@ const NO_HEADER_TEMPLATES = [
36
37
  'NarrowWideDetails',
37
38
  'WideNarrowDetails',
38
39
  'Confirmation',
39
- 'DynamicTabs'
40
+ 'DynamicTabs',
41
+ 'DetailsSubTabs'
40
42
  ];
41
43
 
42
44
  export default function View(props: PropsWithChildren<ViewProps>) {
43
- const { children, template, getPConnect, mode, visibility, name: pageName } = props;
45
+ const { children, template, getPConnect, mode, visibility, name: pageName, type, title } = props;
44
46
  let { label = '', showLabel = false } = props;
47
+ const { PAGE_TYPES: { PAGE, LANDINGPAGE, LISTPAGE } = {}, MODAL } = PCore.getConstants();
45
48
 
46
49
  // Get the inherited props from the parent to determine label settings. For 8.6, this is only for embedded data form views
47
50
  // Putting this logic here instead of copy/paste in every Form template index.js
@@ -49,12 +52,43 @@ export default function View(props: PropsWithChildren<ViewProps>) {
49
52
  const inheritedProps: any = getPConnect().getInheritedProps(); // try to remove any when getInheritedProps typedefs are fixed
50
53
  label = inheritedProps.label || label;
51
54
  showLabel = inheritedProps.showLabel || showLabel;
55
+ const localeUtils = PCore.getLocaleUtils();
52
56
 
53
57
  const isEmbeddedDataView = mode === 'editable'; // would be better to check the reference child for `context` attribute if possible
54
58
  if (isEmbeddedDataView && showLabel === undefined) {
55
59
  showLabel = true;
56
60
  }
57
61
 
62
+ useEffect(() => {
63
+ // Get the localized application label
64
+ let applicationLabel = PCore.getEnvironmentInfo().getApplicationLabel();
65
+ applicationLabel = localeUtils.getLocaleValue(`${applicationLabel}`, '', '');
66
+ const caseInfo = getPConnect().getCaseInfo();
67
+ const isAssignmentInCreateStage = caseInfo && caseInfo.isAssignmentInCreateStage();
68
+ const isRenderingInModal = getPConnect().getContainerName().includes(MODAL);
69
+ const isRenderingInPreviewPanel = getPConnect().getContainerName().includes('preview');
70
+
71
+ /* If assignment is in create stage and rendering in modal don't update the title.
72
+ Title will be updated on completion of create stage and when the assignment is rendered inline to the page.
73
+ */
74
+ const canUpdateTitle =
75
+ !isRenderingInPreviewPanel &&
76
+ (type === PAGE || type === LANDINGPAGE || type === LISTPAGE) &&
77
+ !(isRenderingInModal && isAssignmentInCreateStage) &&
78
+ PCore.getEnvironmentInfo().getRenderingMode() === 'FULL_PORTAL';
79
+ // Incase of home route title is same as applicationLabel so setting to empty to just show applicationLabel
80
+ let titleVar = title === applicationLabel ? '' : title;
81
+
82
+ if (canUpdateTitle) {
83
+ if (caseInfo) {
84
+ const name = caseInfo.getName();
85
+ const id = caseInfo.getBusinessID();
86
+ titleVar = name && id ? `${name} (${id})` : titleVar;
87
+ }
88
+ document.title = titleVar ? `${titleVar} - ${applicationLabel}` : applicationLabel;
89
+ }
90
+ }, [type, title, getPConnect, PAGE, LANDINGPAGE, LISTPAGE]);
91
+
58
92
  const key = `${getPConnect().getContextName()}_${getPConnect().getPageReference()}_${pageName}`;
59
93
  // As long as the template is defined in the dependencies of the view
60
94
  // it will be loaded, otherwise fall back to single column
@@ -0,0 +1,87 @@
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
+ // @ts-ignore
46
+ const cache = PCore.getNavigationUtils().getComponentCache(searchSelectCacheKey) ?? {};
47
+
48
+ const editableFieldComp = firstChildPConnect().createComponent({
49
+ type: firstChildMeta.type,
50
+ config: {
51
+ ...getFirstChildConfig({
52
+ firstChildMeta,
53
+ getPConnect,
54
+ rawViewMetadata,
55
+ contextClass: targetObjectClass,
56
+ dataReferenceConfigToChild,
57
+ isCreateNewReferenceEnabled,
58
+ disableStartingFieldsForReference,
59
+ pyID
60
+ }),
61
+ searchFields,
62
+ showRecords,
63
+ label: localizedVal('Search results', 'DataReference'),
64
+ searchSelectCacheKey,
65
+ cache
66
+ }
67
+ });
68
+
69
+ const { selectionList, dataRelationshipContext } = editableFieldComp.props.getPConnect().getConfigProps();
70
+ const editableField = selectionMode === MULTI ? selectionList.substring(1) : dataRelationshipContext;
71
+
72
+ const searchGroupsProps = {
73
+ getPConnect,
74
+ editableField,
75
+ localeReference,
76
+ setShowRecords,
77
+ searchSelectCacheKey,
78
+ cache
79
+ };
80
+
81
+ return (
82
+ <>
83
+ <SearchGroups {...searchGroupsProps} />
84
+ {editableFieldComp}
85
+ </>
86
+ );
87
+ }
@@ -0,0 +1,58 @@
1
+ const SKIP_CACHE_KEY = '';
2
+
3
+ export function getMappedKey(key) {
4
+ const mappedKey = PCore.getEnvironmentInfo().getKeyMapping(key);
5
+ if (!mappedKey) {
6
+ return key;
7
+ }
8
+ return mappedKey;
9
+ }
10
+
11
+ const getComponentStateKey = (getPConnect, propertyName: string) => {
12
+ const pConnect = getPConnect();
13
+ const caseID = `.${getMappedKey('pyID')}`; // Enhance this later when use-case arrives for data objects using S&S.
14
+ const resolvedCaseID = pConnect.getValue(caseID);
15
+
16
+ if (!resolvedCaseID) {
17
+ return SKIP_CACHE_KEY;
18
+ }
19
+
20
+ return `Search-${resolvedCaseID}-${pConnect.getPageReference()}-${propertyName}-${pConnect.getCurrentView()}`;
21
+ };
22
+
23
+ const getComponentStateOptions = getPConnect => {
24
+ return { clearOnCancelForContext: getPConnect().getContextName() };
25
+ };
26
+
27
+ interface SearchCategory {
28
+ // tabId of search category selected
29
+ selectedCategory: string;
30
+ }
31
+
32
+ interface SearchGroup {
33
+ // searchFields can be any object based on what fields are authored.
34
+ searchFields: unknown;
35
+ activeGroupId: string;
36
+ }
37
+
38
+ const setComponentCache = ({
39
+ cacheKey,
40
+ state,
41
+ options
42
+ }: {
43
+ cacheKey: string;
44
+ state: SearchCategory | SearchGroup;
45
+ options: ReturnType<typeof getComponentStateOptions>;
46
+ }) => {
47
+ if (cacheKey !== SKIP_CACHE_KEY) {
48
+ (PCore.getNavigationUtils() as any).setComponentCache(cacheKey, state, options);
49
+ }
50
+ };
51
+
52
+ const componentCachePersistUtils = {
53
+ getComponentStateKey,
54
+ getComponentStateOptions,
55
+ setComponentCache
56
+ };
57
+
58
+ export default componentCachePersistUtils;
@@ -0,0 +1,245 @@
1
+ import React, { createElement, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { Button, Grid, 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
+ <Grid 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
+ </Grid>
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
+ // eslint-disable-next-line react/no-array-index-key
241
+ <React.Fragment key={index}>{child}</React.Fragment>
242
+ ))}
243
+ </Box>
244
+ );
245
+ }
@@ -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
+ // eslint-disable-next-line import/prefer-default-export
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';