@pega/react-sdk-overrides 0.25.4 → 0.25.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/designSystemExtension/Banner/Banner.tsx +5 -2
- package/lib/designSystemExtension/CaseSummaryFields/CaseSummaryFields.tsx +1 -1
- package/lib/designSystemExtension/RichTextEditor/RichTextEditor.tsx +5 -2
- package/lib/designSystemExtension/WssQuickCreate/WssQuickCreate.css +6 -13
- package/lib/designSystemExtension/WssQuickCreate/WssQuickCreate.tsx +12 -1
- package/lib/field/Group/Group.tsx +3 -1
- package/lib/field/Location/Location.css +4 -0
- package/lib/field/Location/Location.tsx +2 -0
- package/lib/field/RadioButtons/RadioButtons.tsx +1 -1
- package/lib/field/RichText/RichText.css +79 -0
- package/lib/field/RichText/RichText.tsx +2 -0
- package/lib/field/SelectableCard/SelectableCard.tsx +3 -3
- package/lib/field/SelectableCard/utils.tsx +0 -4
- package/lib/field/SemanticLink/SemanticLink.tsx +1 -1
- package/lib/field/UserReference/UserReference.tsx +1 -1
- package/lib/helpers/attachmentShared.ts +6 -0
- package/lib/helpers/formatters/Currency.ts +9 -4
- package/lib/helpers/object-utils.ts +10 -0
- package/lib/infra/Assignment/Assignment.tsx +31 -24
- package/lib/infra/Containers/ModalViewContainer/ModalViewContainer.tsx +2 -1
- package/lib/infra/MultiStep/MultiStep.css +44 -66
- package/lib/infra/MultiStep/MultiStep.tsx +25 -51
- package/lib/infra/View/View.tsx +2 -1
- package/lib/template/AppShell/AppShell.tsx +10 -7
- package/lib/template/CaseSummary/CaseSummary.tsx +26 -38
- package/lib/template/CaseView/CaseView.tsx +20 -15
- package/lib/template/DefaultPage/DefaultPage.tsx +21 -1
- package/lib/template/ListView/ListView.tsx +152 -157
- package/lib/template/SelfServiceCaseView/SelfServiceCaseView.tsx +143 -1
- package/lib/template/SingleReferenceReadOnly/SingleReferenceReadOnly.tsx +9 -1
- package/lib/template/WssNavBar/WssNavBar.tsx +3 -3
- package/lib/template/utils.tsx +58 -0
- package/lib/widget/Attachment/Attachment.tsx +284 -210
- package/lib/widget/Attachment/Attachment.types.ts +96 -0
- package/lib/widget/Attachment/AttachmentUtils.ts +316 -0
- package/lib/widget/FileUtility/FileUtility/FileUtility.tsx +25 -16
- package/lib/widget/ToDo/ToDo.tsx +2 -6
- package/package.json +1 -1
- package/lib/helpers/attachmentHelpers.ts +0 -97
|
@@ -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
|
+
};
|
|
@@ -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, Card } 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/
|
|
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
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: [],
|
|
@@ -210,7 +213,6 @@ export default function FileUtility(props: FileUtilityProps) {
|
|
|
210
213
|
|
|
211
214
|
const getAttachments = () => {
|
|
212
215
|
const attachmentUtils = PCore.getAttachmentUtils();
|
|
213
|
-
const caseID = thePConn.getValue(PCore.getConstants().CASE_INFO.CASE_INFO_ID, ''); // 2nd arg empty string until typedef marked correctly
|
|
214
216
|
|
|
215
217
|
if (caseID && caseID !== '') {
|
|
216
218
|
const attPromise = attachmentUtils.getCaseAttachments(caseID, thePConn.getContextName());
|
|
@@ -245,25 +247,32 @@ export default function FileUtility(props: FileUtilityProps) {
|
|
|
245
247
|
}
|
|
246
248
|
};
|
|
247
249
|
|
|
250
|
+
const debouncedGetAttachments = debounce(getAttachments, 1000);
|
|
251
|
+
|
|
248
252
|
useEffect(() => {
|
|
249
|
-
|
|
253
|
+
debouncedGetAttachments();
|
|
250
254
|
}, []);
|
|
251
255
|
|
|
252
256
|
useEffect(() => {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
);
|
|
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);
|
|
264
267
|
};
|
|
265
268
|
}, []);
|
|
266
269
|
|
|
270
|
+
useEffect(() => {
|
|
271
|
+
thePConn.registerAdditionalProps({
|
|
272
|
+
lastRefreshTime: `@P ${PCore.getConstants().SUMMARY_OF_ATTACHMENTS_LAST_REFRESH_TIME}`
|
|
273
|
+
});
|
|
274
|
+
}, [thePConn]);
|
|
275
|
+
|
|
267
276
|
function setNewFiles(arFiles) {
|
|
268
277
|
let index = 0;
|
|
269
278
|
for (const file of arFiles) {
|
package/lib/widget/ToDo/ToDo.tsx
CHANGED
|
@@ -82,19 +82,15 @@ function getID(assignment: any) {
|
|
|
82
82
|
|
|
83
83
|
const useStyles = makeStyles(theme => ({
|
|
84
84
|
root: {
|
|
85
|
-
marginTop: theme.spacing(1),
|
|
86
85
|
marginBottom: theme.spacing(1),
|
|
87
86
|
paddingBottom: theme.spacing(1),
|
|
88
|
-
|
|
89
|
-
borderLeftColor: theme.palette.primary.light
|
|
87
|
+
borderRadius: 16
|
|
90
88
|
},
|
|
91
89
|
avatar: {
|
|
92
90
|
backgroundColor: theme.palette.primary.light,
|
|
93
91
|
color: theme.palette.getContrastText(theme.palette.primary.light)
|
|
94
92
|
},
|
|
95
93
|
todoWrapper: {
|
|
96
|
-
borderLeft: '6px solid',
|
|
97
|
-
borderLeftColor: theme.palette.primary.light,
|
|
98
94
|
padding: theme.spacing(1),
|
|
99
95
|
margin: theme.spacing(1)
|
|
100
96
|
},
|
|
@@ -307,7 +303,7 @@ export default function ToDo(props: ToDoProps) {
|
|
|
307
303
|
</Avatar>
|
|
308
304
|
<div style={{ display: 'block' }}>
|
|
309
305
|
<Typography variant='h6'>{assignment?.name}</Typography>
|
|
310
|
-
{`${localizedVal('Task in', localeCategory)} ${
|
|
306
|
+
{`${localizedVal('Task in', localeCategory)} ${getID(assignment)} \u2022 ${localizedVal(
|
|
311
307
|
'Urgency',
|
|
312
308
|
localeCategory
|
|
313
309
|
)} ${getPriority(assignment)}`}
|
package/package.json
CHANGED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
import download from 'downloadjs';
|
|
3
|
-
|
|
4
|
-
export const isContentBinary = headers => {
|
|
5
|
-
return headers && headers['content-transfer-encoding'] === 'binary';
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export const isContentBase64 = headers => {
|
|
9
|
-
return headers && headers['content-transfer-encoding'] === 'base64';
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export const fileDownload = (data, fileName, ext, headers) => {
|
|
13
|
-
const name = ext ? `${fileName}.${ext}` : fileName;
|
|
14
|
-
// Temp fix: downloading EMAIl type attachment as html file
|
|
15
|
-
if (ext === 'html') {
|
|
16
|
-
download(isContentBase64(headers) ? atob(data) : data, name, 'text/html');
|
|
17
|
-
} else if (isContentBinary(headers)) {
|
|
18
|
-
download(data, name);
|
|
19
|
-
} else {
|
|
20
|
-
download(atob(data), name);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const fileDownloadVar = (content, type, name, extension) => {
|
|
25
|
-
if (type === 'FILE' || type === undefined) {
|
|
26
|
-
fileDownload(content.data, name, extension, content.headers);
|
|
27
|
-
} else if (type === 'URL') {
|
|
28
|
-
let { data } = content;
|
|
29
|
-
if (!/^(http|https):\/\//.test(data)) {
|
|
30
|
-
data = `//${data}`;
|
|
31
|
-
}
|
|
32
|
-
window.open(content.data, '_blank');
|
|
33
|
-
} else if (type === 'EMAIL') {
|
|
34
|
-
// Temp Fix: for EMAIL type attachment
|
|
35
|
-
fileDownload(content.data, name, 'html', content.headers);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export const useFileDownload = context => {
|
|
40
|
-
return useCallback(
|
|
41
|
-
({ ID, name, extension, type, category, responseType }) => {
|
|
42
|
-
if (category !== 'pxDocument') {
|
|
43
|
-
PCore.getAttachmentUtils()
|
|
44
|
-
.downloadAttachment(ID, context, responseType)
|
|
45
|
-
.then(content => {
|
|
46
|
-
fileDownloadVar(content, type, name, extension);
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
.catch(console.error);
|
|
50
|
-
} else {
|
|
51
|
-
PCore.getAttachmentUtils()
|
|
52
|
-
// @ts-expect-error
|
|
53
|
-
.downloadDocument(ID, context, responseType)
|
|
54
|
-
.then(content => {
|
|
55
|
-
fileDownloadVar(content, type, name, extension);
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
.catch(console.error);
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
[context]
|
|
62
|
-
);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export const getIconFromFileType = (fileType): string => {
|
|
66
|
-
let icon = 'document-doc';
|
|
67
|
-
if (!fileType) return icon;
|
|
68
|
-
if (fileType.startsWith('audio')) {
|
|
69
|
-
icon = 'audio';
|
|
70
|
-
} else if (fileType.startsWith('video')) {
|
|
71
|
-
icon = 'video';
|
|
72
|
-
} else if (fileType.startsWith('image')) {
|
|
73
|
-
icon = 'picture';
|
|
74
|
-
} else if (fileType.includes('pdf')) {
|
|
75
|
-
icon = 'document-pdf';
|
|
76
|
-
} else {
|
|
77
|
-
const [, subtype] = fileType.split('/');
|
|
78
|
-
const foundMatch = sources => {
|
|
79
|
-
return sources.some(key => subtype.includes(key));
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
if (foundMatch(['excel', 'spreadsheet'])) {
|
|
83
|
-
icon = 'document-xls';
|
|
84
|
-
} else if (foundMatch(['zip', 'compressed', 'gzip', 'rar', 'tar'])) {
|
|
85
|
-
icon = 'document-compress';
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return icon;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
export const validateMaxSize = (fileObj: any, maxSizeInMB: string): boolean => {
|
|
93
|
-
const fileSize = (fileObj.size / 1048576).toFixed(2);
|
|
94
|
-
return parseFloat(fileSize) < parseFloat(maxSizeInMB);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
export const isFileUploadedToServer = file => file.responseProps && !file.responseProps.ID?.includes('temp');
|