@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
@@ -0,0 +1,96 @@
1
+ import type { ReactElement, Ref } from 'react';
2
+
3
+ export interface ResponseProps {
4
+ ID: string;
5
+ extension: string;
6
+ createDateTime?: Date | string | number;
7
+ createUser?: string;
8
+ name: string;
9
+ }
10
+
11
+ export interface AttachmentActions {
12
+ rel: string;
13
+ href: string;
14
+ title: string;
15
+ type: string;
16
+ }
17
+
18
+ export interface AttachmentLinks {
19
+ delete: AttachmentActions;
20
+ download: AttachmentActions;
21
+ edit: AttachmentActions;
22
+ }
23
+ export interface FileObject extends File {
24
+ icon?: string;
25
+ ID: string;
26
+ fileName: string;
27
+ category: string;
28
+ responseType: string;
29
+ fileType: string;
30
+ mimeType: string;
31
+ extension: string;
32
+ thumbnail?: string;
33
+ nameWithExt: string;
34
+ inProgress?: boolean;
35
+ progress?: number;
36
+ handle: string;
37
+ label: string;
38
+ delete?: boolean;
39
+ error?: boolean;
40
+ description: string;
41
+
42
+ props: {
43
+ icon?: string;
44
+
45
+ ref?: Ref<HTMLDivElement>;
46
+ id: string;
47
+ error?: string;
48
+ format?: string;
49
+ name: string;
50
+ thumbnail?: string;
51
+ onPreview?: () => void;
52
+ onDelete?: () => void;
53
+ onOpen?: () => void;
54
+ onEdit?: () => void;
55
+ onCancel?: () => void;
56
+ };
57
+ responseProps: ResponseProps;
58
+ value?: {
59
+ filename: string;
60
+ ID: string;
61
+ thumbnail: string;
62
+ };
63
+ categoryName: string;
64
+ createTime: string;
65
+ createdBy: string;
66
+ createdByName: string;
67
+ links: AttachmentLinks;
68
+ name: string;
69
+ meta?: ReactElement;
70
+ }
71
+
72
+ export interface ReduxAttachments {
73
+ ID?: string;
74
+ pzInsKey?: string;
75
+ FileName: string;
76
+ Category: string;
77
+ MimeType?: string;
78
+ FileExtension: string;
79
+ error: string | null;
80
+ localAttachment: boolean;
81
+ thumbnail?: string;
82
+ fileIndex?: number;
83
+ instruction?: string;
84
+ }
85
+
86
+ export interface PageInstructionOptions {
87
+ allowMultiple: boolean;
88
+ isMultiAttachmentInInlineEditTable: boolean;
89
+ attachmentCount: number;
90
+ insertPageInstruction: boolean;
91
+ deletePageInstruction: boolean;
92
+ deleteIndex: number;
93
+ insertRedux: boolean;
94
+ isOldAttachment: boolean;
95
+ deleteRedux: boolean;
96
+ }
@@ -0,0 +1,316 @@
1
+ import { useCallback, useRef } from 'react';
2
+ import download from 'downloadjs';
3
+ import equal from 'fast-deep-equal';
4
+
5
+ import type { FileObject, PageInstructionOptions, ReduxAttachments } from './Attachment.types';
6
+
7
+ export const isContentBinary = (headers: Record<string, string>) => {
8
+ return headers && headers['content-transfer-encoding'] === 'binary';
9
+ };
10
+
11
+ export const isContentBase64 = (headers: Record<string, string>) => {
12
+ return headers && headers['content-transfer-encoding'] === 'base64';
13
+ };
14
+
15
+ export const validateFileExtension = (fileObj: Record<string, string>, allowedExtensions: string) => {
16
+ if (!allowedExtensions) {
17
+ return true;
18
+ }
19
+ const allowedExtensionList = allowedExtensions
20
+ .toLowerCase()
21
+ .split(',')
22
+ .map(item => item.replaceAll('.', '').trim());
23
+ const extension = fileObj.name.split('.').pop()?.toLowerCase() || '';
24
+ return allowedExtensionList.includes(extension);
25
+ };
26
+
27
+ export const fileDownload = (data: string | Blob, fileName: string, ext: string | null, headers: Record<string, string>) => {
28
+ const name = ext ? `${fileName}.${ext}` : fileName;
29
+ // Temp fix: downloading EMAIl type attachment as html file
30
+ if (ext === 'html') {
31
+ download(isContentBase64(headers) ? atob(data as string) : data, name, 'text/html');
32
+ } else if (isContentBinary(headers)) {
33
+ download(data, name);
34
+ } else {
35
+ download(atob(data as string), name);
36
+ }
37
+ };
38
+
39
+ export const getIconFromFileType = (fileType: string) => {
40
+ let icon = 'document-doc';
41
+ if (!fileType) return icon;
42
+ if (fileType.startsWith('audio')) {
43
+ icon = 'audio';
44
+ } else if (fileType.startsWith('video')) {
45
+ icon = 'video';
46
+ } else if (fileType.startsWith('image')) {
47
+ icon = 'picture';
48
+ } else if (fileType.includes('pdf')) {
49
+ icon = 'document-pdf';
50
+ } else {
51
+ const [, subtype] = fileType.split('/');
52
+ const foundMatch = (sources: string[]) => {
53
+ return sources.some(key => subtype.includes(key));
54
+ };
55
+
56
+ if (foundMatch(['excel', 'spreadsheet'])) {
57
+ icon = 'document-xls';
58
+ } else if (foundMatch(['zip', 'compressed', 'gzip', 'rar', 'tar'])) {
59
+ icon = 'document-compress';
60
+ }
61
+ }
62
+
63
+ return icon;
64
+ };
65
+
66
+ export const fileDownloadVar = (content: { data: string; headers: Record<string, string> }, type: string, name: string, extension: string) => {
67
+ if (type === 'FILE' || type === undefined) {
68
+ fileDownload(content.data, name, extension, content.headers);
69
+ } else if (type === 'URL') {
70
+ let { data } = content;
71
+ if (!/^(http|https):\/\//.test(data)) {
72
+ data = `//${data}`;
73
+ }
74
+ window.open(content.data, '_blank');
75
+ } else if (type === 'EMAIL') {
76
+ // Temp Fix: for EMAIL type attachment
77
+ fileDownload(content.data, name, 'html', content.headers);
78
+ }
79
+ };
80
+
81
+ export const getMappedValue = (value: string): string => {
82
+ return PCore.getEnvironmentInfo().getKeyMapping(value) ?? value;
83
+ };
84
+
85
+ const generateInstructions = (
86
+ files: FileObject[],
87
+ pConn: typeof PConnect,
88
+ attachmentsInModal: ReduxAttachments[] | Pick<ReduxAttachments, 'instruction' | 'fileIndex'>[],
89
+ options: {
90
+ allowMultiple: boolean;
91
+ isMultiAttachmentInInlineEditTable: boolean;
92
+ attachmentCount: number;
93
+ insertPageInstruction: boolean;
94
+ deletePageInstruction: boolean;
95
+ deleteIndex: number;
96
+ }
97
+ ) => {
98
+ const { allowMultiple, isMultiAttachmentInInlineEditTable, attachmentCount, insertPageInstruction, deletePageInstruction, deleteIndex } = options;
99
+ const transformedAttachments: ReduxAttachments[] = [];
100
+ let valueRef = pConn.getStateProps().value;
101
+ valueRef = valueRef?.indexOf('.') === 0 ? valueRef.substring(1) : valueRef;
102
+ const uniqueKey = getMappedValue('pzInsKey');
103
+ files.forEach((file, index) => {
104
+ const filename = file.value?.filename || file.props?.name || '';
105
+ const payload = {
106
+ [uniqueKey]: file.value?.ID || file.props?.id,
107
+ FileName: filename,
108
+ Category: '',
109
+ // MimeType: getMimeTypeFromFile(filename),
110
+ FileExtension: filename.split('.').pop() ?? filename,
111
+ error: file.props?.error || null,
112
+ localAttachment: true,
113
+ thumbnail: file.value?.thumbnail
114
+ };
115
+ transformedAttachments.push(payload);
116
+ if (payload.error) {
117
+ return; // Don't process page instructions for error files, skip current iteration
118
+ }
119
+ if (allowMultiple) {
120
+ if (isMultiAttachmentInInlineEditTable) {
121
+ if (insertPageInstruction) {
122
+ attachmentsInModal.push({ ...payload, instruction: 'insert' } as any);
123
+ } else if (deletePageInstruction) {
124
+ (attachmentsInModal as Pick<ReduxAttachments, 'instruction' | 'fileIndex'>[]).push({
125
+ instruction: 'delete',
126
+ fileIndex: deleteIndex
127
+ });
128
+ }
129
+ } else if (insertPageInstruction) {
130
+ pConn.getListActions().insert({ ID: payload[uniqueKey] }, attachmentCount + index, undefined, {
131
+ skipStateUpdate: true
132
+ });
133
+ } else if (deletePageInstruction) {
134
+ pConn.getListActions().deleteEntry(deleteIndex, undefined, { skipStateUpdate: true });
135
+ }
136
+ } else if (insertPageInstruction) {
137
+ pConn.getListActions().replacePage(`.${valueRef}`, { ID: payload[uniqueKey] }, { skipStateUpdate: true });
138
+ } else if (deletePageInstruction) {
139
+ pConn.getListActions().deletePage(`.${valueRef}`, { skipStateUpdate: true });
140
+ }
141
+ });
142
+ return transformedAttachments;
143
+ };
144
+
145
+ export const updateReduxState = (
146
+ transformedAttachments: ReduxAttachments[],
147
+ pConn: typeof PConnect,
148
+ valueRef: string,
149
+ options: PageInstructionOptions
150
+ ) => {
151
+ const { allowMultiple, isOldAttachment, insertRedux, deleteRedux } = options;
152
+ let deleteIndex = -1;
153
+
154
+ if (allowMultiple || isOldAttachment) {
155
+ transformedAttachments.forEach(attachment => {
156
+ const key = isOldAttachment ? `${valueRef}.pxResults` : valueRef;
157
+ const existingAttachments: ReduxAttachments[] = PCore.getStoreValue(`.${key}`, pConn.getPageReference(), pConn.getContextName()) || [];
158
+
159
+ if (insertRedux) {
160
+ const actionPayLoad = {
161
+ type: 'LIST_ACTION',
162
+ payload: {
163
+ instruction: 'INSERT',
164
+ context: pConn.getContextName(),
165
+ referenceList: `${pConn.getPageReference()}.${key}`,
166
+ listIndex: existingAttachments.length,
167
+ content: attachment
168
+ }
169
+ };
170
+ PCore.getStore()?.dispatch(actionPayLoad);
171
+ } else if (deleteRedux) {
172
+ const uniqueKey = getMappedValue('pzInsKey');
173
+ deleteIndex = existingAttachments.findIndex(
174
+ existingAttachment =>
175
+ existingAttachment[uniqueKey as keyof ReduxAttachments] === transformedAttachments[0][uniqueKey as keyof ReduxAttachments]
176
+ );
177
+ const actionPayLoad = {
178
+ type: 'LIST_ACTION',
179
+ payload: {
180
+ instruction: 'DELETE',
181
+ context: pConn.getContextName(),
182
+ referenceList: `${pConn.getPageReference()}.${key}`,
183
+ listIndex: deleteIndex
184
+ }
185
+ };
186
+ PCore.getStore()?.dispatch(actionPayLoad);
187
+ }
188
+ });
189
+ } else if (insertRedux) {
190
+ const actionPayLoad = {
191
+ type: 'LIST_ACTION',
192
+ payload: {
193
+ instruction: 'REPLACE',
194
+ context: pConn.getContextName(),
195
+ referenceList: `${pConn.getPageReference()}.${valueRef}`,
196
+ content: transformedAttachments[0]
197
+ }
198
+ };
199
+ PCore.getStore()?.dispatch(actionPayLoad);
200
+ } else if (deleteRedux) {
201
+ const actionPayLoad = {
202
+ type: 'LIST_ACTION',
203
+ payload: {
204
+ instruction: 'DELETEPAGE',
205
+ context: pConn.getContextName(),
206
+ referenceList: `${pConn.getPageReference()}.${valueRef}`
207
+ }
208
+ };
209
+ PCore.getStore()?.dispatch(actionPayLoad);
210
+ }
211
+ };
212
+
213
+ export const insertAttachments = (
214
+ files: FileObject[],
215
+ pConn: typeof PConnect,
216
+ attachmentsInModal: ReduxAttachments[],
217
+ options: PageInstructionOptions
218
+ ) => {
219
+ const { isMultiAttachmentInInlineEditTable } = options;
220
+ let valueRef = pConn.getStateProps().value;
221
+ valueRef = valueRef?.indexOf('.') === 0 ? valueRef.substring(1) : valueRef;
222
+ const transformedAttachments = generateInstructions(files, pConn, attachmentsInModal, {
223
+ ...options,
224
+ insertPageInstruction: true
225
+ });
226
+
227
+ if (isMultiAttachmentInInlineEditTable) {
228
+ return; // For attachments within modal, redux update is not necessary yet, as modal isn't submitted at this stage
229
+ }
230
+ updateReduxState(transformedAttachments, pConn, valueRef, { ...options, insertRedux: true });
231
+ };
232
+
233
+ export const deleteAttachments = (
234
+ files: FileObject[],
235
+ pConn: typeof PConnect,
236
+ attachmentsInModal: Pick<ReduxAttachments, 'instruction' | 'fileIndex'>[],
237
+ options: PageInstructionOptions
238
+ ) => {
239
+ const { isMultiAttachmentInInlineEditTable } = options;
240
+ let valueRef = pConn.getStateProps().value;
241
+ valueRef = valueRef?.indexOf('.') === 0 ? valueRef.substring(1) : valueRef;
242
+ const transformedAttachments = generateInstructions(files, pConn, attachmentsInModal, {
243
+ ...options,
244
+ deletePageInstruction: true
245
+ });
246
+
247
+ if (isMultiAttachmentInInlineEditTable) {
248
+ return; // For attachments within modal, redux update is not necessary yet, as modal isn't submitted at this stage
249
+ }
250
+ updateReduxState(transformedAttachments, pConn, valueRef, { ...options, deleteRedux: true });
251
+ };
252
+
253
+ export const clearFieldErrorMessages = (pConn: typeof PConnect) => {
254
+ const fieldName = pConn.getStateProps().value;
255
+ PCore.getMessageManager().clearMessages({
256
+ type: PCore.getConstants().MESSAGES.MESSAGES_TYPE_ERROR,
257
+ property: fieldName,
258
+ pageReference: pConn.getPageReference(),
259
+ context: pConn.getContextName()
260
+ });
261
+ };
262
+
263
+ export const useFileDownload = (context: string) => {
264
+ return useCallback(
265
+ ({
266
+ ID,
267
+ name,
268
+ extension,
269
+ type,
270
+ category,
271
+ responseType
272
+ }: {
273
+ ID: string;
274
+ name: string;
275
+ extension: string;
276
+ type: string;
277
+ category: string;
278
+ responseType: string;
279
+ }) => {
280
+ if (category !== 'pxDocument') {
281
+ (
282
+ PCore.getAttachmentUtils().downloadAttachment(ID, context, responseType) as Promise<{
283
+ data: string;
284
+ headers: Record<string, string>;
285
+ }>
286
+ )
287
+ .then(content => {
288
+ fileDownloadVar(content, type, name, extension);
289
+ })
290
+
291
+ .catch(console.error);
292
+ } else {
293
+ (
294
+ PCore.getAttachmentUtils().downloadDocument(ID, context) as Promise<{
295
+ data: string;
296
+ headers: Record<string, string>;
297
+ }>
298
+ )
299
+ .then(content => {
300
+ fileDownloadVar(content, type, name, extension);
301
+ })
302
+
303
+ .catch(console.error);
304
+ }
305
+ },
306
+ [context]
307
+ );
308
+ };
309
+
310
+ export const useDeepMemo = (memoFn, key) => {
311
+ const ref: any = useRef();
312
+ if (!ref.current || !equal(key, ref.current.key)) {
313
+ ref.current = { key, value: memoFn() };
314
+ }
315
+ return ref.current.value;
316
+ };
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useRef, useState } from 'react';
2
- import { Theme } from '@mui/material/styles';
2
+ import type { Theme } from '@mui/material/styles';
3
3
  import withStyles from '@mui/styles/withStyles';
4
4
  import createStyles from '@mui/styles/createStyles';
5
5
  import Table from '@mui/material/Table';
@@ -11,7 +11,7 @@ import TableRow from '@mui/material/TableRow';
11
11
  import isDeepEqual from 'fast-deep-equal/react';
12
12
 
13
13
  import { Utils } from '@pega/react-sdk-components/lib/components/helpers/utils';
14
- import { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
14
+ import type { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
15
15
 
16
16
  interface CaseHistoryProps extends PConnProps {
17
17
  // If any, enter additional props that only exist on this component
@@ -66,8 +66,8 @@ export default function CaseHistory(props: CaseHistoryProps) {
66
66
  const dataViewName = 'D_pyWorkHistory';
67
67
  const context = thePConn.getContextName();
68
68
 
69
- function computeRowData(rows: Object[]): void {
70
- const theRowData: Object[] = [];
69
+ function computeRowData(rows: object[]): void {
70
+ const theRowData: object[] = [];
71
71
 
72
72
  rows.forEach((row: any, rowIndex: number) => {
73
73
  // Now, for each property in the index of row properties (displayedColumns), add an object
@@ -142,7 +142,7 @@ export default function CaseHistory(props: CaseHistoryProps) {
142
142
  // Note: using rowData.current since we're using useRef as a mutatable
143
143
  // value that's only updated when it changes.
144
144
  if (rowData.current.length > 0) {
145
- rowData.current.forEach((dataRow: Object[], index) => {
145
+ rowData.current.forEach((dataRow: object[], index) => {
146
146
  // using dataRow[0]-dataRow[1] as the array key since it's a unique value
147
147
  const theKey = `CaseHistory-${index}`;
148
148
  theDataRows.push(
@@ -11,17 +11,3 @@
11
11
  justify-content: center;
12
12
  display: flex;
13
13
  }
14
-
15
- .primary-button {
16
- background-color: #3f51b5 !important;
17
- color: white !important;
18
- padding: 6px 14px !important;
19
- text-transform: unset !important;
20
- font-size: 14px;
21
- }
22
-
23
- .secondary-button {
24
- box-shadow: 0px 5px 10px 0px rgb(0 0 0 / 20%);
25
- text-transform: unset !important;
26
- padding: 6px 14px !important;
27
- }
@@ -1,5 +1,5 @@
1
1
  import { Button } from '@mui/material';
2
- import { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
2
+ import type { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
3
3
  import './ActionButtonsForFileUtil.css';
4
4
 
5
5
  interface ActionButtonsForFileUtilProps extends PConnProps {
@@ -15,14 +15,14 @@ export default function ActionButtonsForFileUtil(props: ActionButtonsForFileUtil
15
15
  <div className='psdk-actions'>
16
16
  <div className='psdk-action-buttons'>
17
17
  {props.arSecondaryButtons.map(file => (
18
- <Button className='secondary-button' key={file.actionID} onClick={props.secondaryAction}>
18
+ <Button className='secondary-button' color='secondary' variant='contained' key={file.actionID} onClick={props.secondaryAction}>
19
19
  {file.name}
20
20
  </Button>
21
21
  ))}
22
22
  </div>
23
23
  <div className='psdk-action-buttons'>
24
24
  {props.arMainButtons.map(file => (
25
- <Button className='primary-button' key={file.actionID} onClick={props.primaryAction}>
25
+ <Button className='primary-button' color='primary' variant='contained' key={file.actionID} onClick={props.primaryAction}>
26
26
  {file.name}
27
27
  </Button>
28
28
  ))}
@@ -2,7 +2,7 @@
2
2
  width: 100%;
3
3
  padding: 0.625rem 0rem;
4
4
  text-align: left;
5
- background-color: white;
5
+ /* background-color: var(--utility-background-color); */
6
6
  border-radius: 0.6125rem;
7
7
  margin: 0.3125rem 0rem;
8
8
  position: relative;
@@ -16,6 +16,7 @@
16
16
  .psdk-file-utility-card-svg-icon {
17
17
  width: 1.4rem;
18
18
  display: inline-block;
19
+ filter: var(--svg-color);
19
20
  }
20
21
 
21
22
  .header-text {
@@ -25,7 +26,7 @@
25
26
  }
26
27
 
27
28
  .psdk-utility-count {
28
- background: #65b5f5;
29
+ background: var(--utility-count-background-color);
29
30
  border-radius: calc(1.125 * 0.5rem);
30
31
  font-size: 0.75rem;
31
32
  font-weight: bold;
@@ -40,7 +41,7 @@
40
41
  align-items: center;
41
42
  height: 100%;
42
43
  width: 100%;
43
- background-color: rgba(100, 100, 100, 0.4);
44
+ background-color: var(--modal-background-color);
44
45
  position: fixed;
45
46
  z-index: 999;
46
47
  top: 0px;
@@ -51,11 +52,11 @@
51
52
  display: table;
52
53
  margin: auto;
53
54
  min-width: 650px;
54
- background-color: white;
55
- border: 1px solid black;
55
+ background-color: var(--modal-top-color);
56
+ border: 1px solid var(--modal-border-color);
56
57
  border-radius: 10px;
57
58
  padding: 20px;
58
- box-shadow: 0 0 10px 3px #777;
59
+ box-shadow: 0 0 10px 3px var(--modal-box-shadow-color);
59
60
  }
60
61
 
61
62
  .psdk-modal-file-selector {
@@ -7,15 +7,17 @@ import download from 'downloadjs';
7
7
  // import SummaryList from '../../SummaryList';
8
8
  // import ActionButtonsForFileUtil from '../ActionButtonsForFileUtil';
9
9
  import './FileUtility.css';
10
- import { IconButton, Menu, MenuItem, Button, CircularProgress } from '@mui/material';
10
+ import { IconButton, Menu, MenuItem, Button, CircularProgress, Card, debounce } from '@mui/material';
11
11
  import MoreVertIcon from '@mui/icons-material/MoreVert';
12
12
 
13
- import { validateMaxSize } from '@pega/react-sdk-components/lib/components/helpers/attachmentHelpers';
13
+ import { validateMaxSize } from '@pega/react-sdk-components/lib/components/helpers/attachmentShared';
14
+ import { getResolvedConstantValue } from '@pega/react-sdk-components/lib/components/helpers/object-utils';
14
15
  import { getComponentFromMap } from '@pega/react-sdk-components/lib/bridge/helpers/sdk_component_map';
15
- import { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
16
+ import type { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
16
17
 
17
18
  interface FileUtilityProps extends PConnProps {
18
19
  // If any, enter additional props that only exist on this component
20
+ caseId?: string;
19
21
  }
20
22
 
21
23
  export default function FileUtility(props: FileUtilityProps) {
@@ -23,8 +25,9 @@ export default function FileUtility(props: FileUtilityProps) {
23
25
  const SummaryList = getComponentFromMap('SummaryList');
24
26
  const ActionButtonsForFileUtil = getComponentFromMap('ActionButtonsForFileUtil');
25
27
 
26
- const { getPConnect } = props;
28
+ const { getPConnect, caseId } = props;
27
29
  const thePConn = getPConnect();
30
+ const caseID = caseId ?? getResolvedConstantValue(thePConn, PCore.getConstants().CASE_INFO.CASE_INFO_ID);
28
31
  const required = true;
29
32
  const listTemp = {
30
33
  data: [],
@@ -179,7 +182,7 @@ export default function FileUtility(props: FileUtilityProps) {
179
182
  const context = thePConn.getContextName();
180
183
 
181
184
  attachUtils
182
- // @ts-ignore - 3rd parameter "responseEncoding" is optional
185
+ // @ts-expect-error - 3rd parameter "responseEncoding" is optional
183
186
  .downloadAttachment(ID, context)
184
187
  .then((content: any) => {
185
188
  if (type === 'FILE') {
@@ -203,7 +206,6 @@ export default function FileUtility(props: FileUtilityProps) {
203
206
  attachUtils
204
207
  .deleteAttachment(ID, context)
205
208
  .then(() => {
206
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
207
209
  getAttachments();
208
210
  })
209
211
  .catch();
@@ -211,7 +213,6 @@ export default function FileUtility(props: FileUtilityProps) {
211
213
 
212
214
  const getAttachments = () => {
213
215
  const attachmentUtils = PCore.getAttachmentUtils();
214
- const caseID = thePConn.getValue(PCore.getConstants().CASE_INFO.CASE_INFO_ID, ''); // 2nd arg empty string until typedef marked correctly
215
216
 
216
217
  if (caseID && caseID !== '') {
217
218
  const attPromise = attachmentUtils.getCaseAttachments(caseID, thePConn.getContextName());
@@ -246,25 +247,32 @@ export default function FileUtility(props: FileUtilityProps) {
246
247
  }
247
248
  };
248
249
 
250
+ const debouncedGetAttachments = debounce(getAttachments, 1000);
251
+
249
252
  useEffect(() => {
250
- getAttachments();
253
+ debouncedGetAttachments();
251
254
  }, []);
252
255
 
253
256
  useEffect(() => {
254
- PCore.getPubSubUtils().subscribe(
255
- (PCore.getEvents().getCaseEvent() as any).CASE_ATTACHMENTS_UPDATED_FROM_CASEVIEW,
256
- getAttachments,
257
- 'caseAttachmentsUpdateFromCaseview'
258
- );
259
-
260
- return () => {
261
- PCore.getPubSubUtils().unsubscribe(
262
- (PCore.getEvents().getCaseEvent() as any).CASE_ATTACHMENTS_UPDATED_FROM_CASEVIEW,
263
- 'caseAttachmentsUpdateFromCaseview'
264
- );
257
+ const attachSubObject = {
258
+ matcher: 'ATTACHMENTS',
259
+ criteria: {
260
+ ID: caseID
261
+ }
262
+ };
263
+ const attachSubId = PCore.getMessagingServiceManager().subscribe(attachSubObject, debouncedGetAttachments, getPConnect().getContextName());
264
+
265
+ return function cleanup() {
266
+ PCore.getMessagingServiceManager().unsubscribe(attachSubId);
265
267
  };
266
268
  }, []);
267
269
 
270
+ useEffect(() => {
271
+ thePConn.registerAdditionalProps({
272
+ lastRefreshTime: `@P ${PCore.getConstants().SUMMARY_OF_ATTACHMENTS_LAST_REFRESH_TIME}`
273
+ });
274
+ }, [thePConn]);
275
+
268
276
  function setNewFiles(arFiles) {
269
277
  let index = 0;
270
278
  for (const file of arFiles) {
@@ -488,7 +496,7 @@ export default function FileUtility(props: FileUtilityProps) {
488
496
  }
489
497
 
490
498
  return (
491
- <div className='psdk-utility' id='file-utility'>
499
+ <Card className='psdk-utility' id='file-utility'>
492
500
  {inProgress && (
493
501
  <div className='progress-div'>
494
502
  <CircularProgress />
@@ -630,7 +638,6 @@ export default function FileUtility(props: FileUtilityProps) {
630
638
  <div className='psdk-modal-file-top'>
631
639
  <div className='psdk-view-all-header'>
632
640
  <h3>{thePConn.getLocalizedValue('Attachments', '', '')}</h3> {/* 2nd and 3rd args empty string until typedef marked correctly */}
633
- {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
634
641
  <button type='button' className='psdk-close-button' onClick={() => setViewAll(false)}>
635
642
  <img className='psdk-utility-card-actions-svg-icon' src={closeSvgIcon} />
636
643
  </button>
@@ -641,6 +648,6 @@ export default function FileUtility(props: FileUtilityProps) {
641
648
  </div>
642
649
  </div>
643
650
  )}
644
- </div>
651
+ </Card>
645
652
  );
646
653
  }
@@ -1,7 +1,7 @@
1
- import { PropsWithChildren } from 'react';
1
+ import type { PropsWithChildren } from 'react';
2
2
  import { Card, CardContent, CardHeader, Typography } from '@mui/material';
3
3
  import makeStyles from '@mui/styles/makeStyles';
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 FollowersProps extends PConnProps {
7
7
  // If any, enter additional props that only exist on this component
@@ -17,8 +17,6 @@ const useStyles = makeStyles(theme => ({
17
17
  marginLeft: theme.spacing(1),
18
18
  marginTop: theme.spacing(1),
19
19
  marginBottom: theme.spacing(1)
20
- // borderLeft: "6px solid",
21
- // borderLeftColor: green[300]
22
20
  }
23
21
  }));
24
22