@pega/angular-sdk-overrides 0.25.1 → 0.25.3

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 (160) hide show
  1. package/lib/designSystemExtension/alert/alert.component.scss +3 -3
  2. package/lib/designSystemExtension/banner/banner.component.scss +12 -2
  3. package/lib/designSystemExtension/material-case-summary/material-case-summary.component.html +6 -3
  4. package/lib/designSystemExtension/material-case-summary/material-case-summary.component.scss +5 -34
  5. package/lib/designSystemExtension/material-details/material-details.component.scss +0 -5
  6. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.html +2 -2
  7. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.scss +4 -3
  8. package/lib/designSystemExtension/material-summary-item/material-summary-item.component.scss +2 -17
  9. package/lib/designSystemExtension/material-utility/material-utility.component.scss +1 -2
  10. package/lib/designSystemExtension/material-vertical-tabs/material-vertical-tabs.component.scss +1 -1
  11. package/lib/designSystemExtension/operator/operator.component.html +1 -1
  12. package/lib/designSystemExtension/operator/operator.component.scss +3 -10
  13. package/lib/designSystemExtension/operator/operator.component.ts +0 -1
  14. package/lib/designSystemExtension/pulse/pulse.component.scss +2 -2
  15. package/lib/designSystemExtension/rich-text-editor/rich-text-editor.component.scss +0 -1
  16. package/lib/designSystemExtension/wss-quick-create/wss-quick-create.component.scss +16 -8
  17. package/lib/field/auto-complete/auto-complete.component.html +0 -1
  18. package/lib/field/auto-complete/auto-complete.component.ts +35 -172
  19. package/lib/field/cancel-alert/cancel-alert.component.html +8 -12
  20. package/lib/field/cancel-alert/cancel-alert.component.scss +2 -3
  21. package/lib/field/cancel-alert/cancel-alert.component.ts +24 -36
  22. package/lib/field/check-box/check-box.component.html +0 -1
  23. package/lib/field/check-box/check-box.component.scss +0 -1
  24. package/lib/field/check-box/check-box.component.ts +19 -149
  25. package/lib/field/currency/currency.component.ts +36 -168
  26. package/lib/field/date/date.component.html +1 -1
  27. package/lib/field/date/date.component.ts +30 -150
  28. package/lib/field/date-time/date-time.component.ts +31 -149
  29. package/lib/field/decimal/decimal.component.ts +38 -163
  30. package/lib/field/dropdown/dropdown.component.ts +29 -151
  31. package/lib/field/email/email.component.ts +16 -155
  32. package/lib/field/field.base.ts +149 -0
  33. package/lib/field/group/group.component.ts +7 -4
  34. package/lib/field/integer/integer.component.ts +18 -157
  35. package/lib/field/location/location.component.ts +1 -1
  36. package/lib/field/multiselect/multiselect.component.ts +46 -148
  37. package/lib/field/multiselect/utils.ts +55 -47
  38. package/lib/field/object-reference/object-reference.component.html +17 -0
  39. package/lib/field/object-reference/object-reference.component.scss +0 -0
  40. package/lib/field/object-reference/object-reference.component.spec.ts +22 -0
  41. package/lib/field/object-reference/object-reference.component.ts +237 -0
  42. package/lib/field/percentage/percentage.component.ts +37 -154
  43. package/lib/field/phone/phone.component.ts +28 -142
  44. package/lib/field/radio-buttons/radio-buttons.component.scss +4 -2
  45. package/lib/field/radio-buttons/radio-buttons.component.ts +35 -161
  46. package/lib/field/rich-text/rich-text.component.ts +19 -90
  47. package/lib/field/scalar-list/scalar-list.component.ts +17 -72
  48. package/lib/field/selectable-card/selectable-card.component.html +54 -24
  49. package/lib/field/selectable-card/selectable-card.component.scss +11 -0
  50. package/lib/field/selectable-card/selectable-card.component.ts +16 -52
  51. package/lib/field/semantic-link/semantic-link.component.html +4 -8
  52. package/lib/field/semantic-link/semantic-link.component.scss +0 -13
  53. package/lib/field/semantic-link/semantic-link.component.ts +165 -5
  54. package/lib/field/text/text.component.scss +0 -1
  55. package/lib/field/text-area/text-area.component.ts +18 -152
  56. package/lib/field/text-input/text-input.component.ts +16 -155
  57. package/lib/field/time/time.component.ts +17 -151
  58. package/lib/field/url/url.component.ts +16 -154
  59. package/lib/field/user-reference/user-reference.component.scss +0 -1
  60. package/lib/field/user-reference/user-reference.component.ts +2 -3
  61. package/lib/infra/Containers/flow-container/flow-container.component.ts +5 -7
  62. package/lib/infra/Containers/modal-view-container/modal-view-container.component.ts +5 -10
  63. package/lib/infra/Containers/view-container/helper.ts +35 -2
  64. package/lib/infra/Containers/view-container/view-container.component.ts +1 -1
  65. package/lib/infra/action-buttons/action-buttons.component.html +13 -8
  66. package/lib/infra/action-buttons/action-buttons.component.scss +23 -0
  67. package/lib/infra/action-buttons/action-buttons.component.ts +1 -2
  68. package/lib/infra/assignment/assignment.component.ts +8 -6
  69. package/lib/infra/assignment-card/assignment-card.component.html +1 -2
  70. package/lib/infra/assignment-card/assignment-card.component.scss +0 -4
  71. package/lib/infra/assignment-card/assignment-card.component.ts +21 -4
  72. package/lib/infra/defer-load/defer-load.component.html +6 -2
  73. package/lib/infra/defer-load/defer-load.component.ts +16 -10
  74. package/lib/infra/multi-step/multi-step.component.scss +1 -21
  75. package/lib/infra/navbar/navbar.component.html +25 -28
  76. package/lib/infra/navbar/navbar.component.scss +16 -4
  77. package/lib/infra/navbar/navbar.component.ts +8 -3
  78. package/lib/infra/root-container/root-container.component.scss +0 -1
  79. package/lib/infra/root-container/root-container.component.ts +1 -2
  80. package/lib/infra/stages/stages.component.html +2 -2
  81. package/lib/infra/stages/stages.component.scss +7 -35
  82. package/lib/infra/stages/stages.component.ts +4 -2
  83. package/lib/infra/view/view.component.html +1 -1
  84. package/lib/infra/view/view.component.ts +0 -2
  85. package/lib/template/advanced-search/advanced-search.component.html +12 -0
  86. package/lib/template/advanced-search/advanced-search.component.scss +0 -0
  87. package/lib/template/advanced-search/advanced-search.component.spec.ts +0 -0
  88. package/lib/template/advanced-search/advanced-search.component.ts +112 -0
  89. package/lib/template/advanced-search/advanced-search.service.ts +27 -0
  90. package/lib/template/advanced-search/search-group/persist-utils.ts +56 -0
  91. package/lib/template/advanced-search/search-groups/search-groups.component.html +32 -0
  92. package/lib/template/advanced-search/search-groups/search-groups.component.scss +0 -0
  93. package/lib/template/advanced-search/search-groups/search-groups.component.spec.ts +0 -0
  94. package/lib/template/advanced-search/search-groups/search-groups.component.ts +294 -0
  95. package/lib/template/advanced-search/search-groups/utils.ts +29 -0
  96. package/lib/template/app-shell/app-shell.component.html +4 -1
  97. package/lib/template/app-shell/app-shell.component.scss +0 -3
  98. package/lib/template/app-shell/app-shell.component.ts +46 -7
  99. package/lib/template/case-summary/case-summary.component.scss +0 -2
  100. package/lib/template/case-view/case-view.component.html +3 -3
  101. package/lib/template/case-view/case-view.component.scss +18 -10
  102. package/lib/template/case-view/case-view.component.ts +1 -1
  103. package/lib/template/data-reference/data-reference-advanced-search.service.ts +16 -0
  104. package/lib/template/data-reference/data-reference.component.html +11 -8
  105. package/lib/template/data-reference/data-reference.component.ts +346 -112
  106. package/lib/template/data-reference/search-form/search-form.component.html +39 -0
  107. package/lib/template/data-reference/search-form/search-form.component.scss +11 -0
  108. package/lib/template/data-reference/search-form/search-form.component.spec.ts +0 -0
  109. package/lib/template/data-reference/search-form/search-form.component.ts +167 -0
  110. package/lib/template/data-reference/search-form/tabsData.ts +160 -0
  111. package/lib/template/data-reference/utils.ts +92 -0
  112. package/lib/template/default-form/default-form.component.ts +10 -2
  113. package/lib/template/default-page/default-page.component.html +34 -0
  114. package/lib/template/default-page/default-page.component.scss +31 -0
  115. package/lib/template/default-page/default-page.component.spec.ts +24 -0
  116. package/lib/template/default-page/default-page.component.ts +64 -0
  117. package/lib/template/field-group-list/field-group-list.component.scss +0 -1
  118. package/lib/template/inline-dashboard-page/inline-dashboard-page.component.ts +1 -1
  119. package/lib/template/list-view/list-view.component.html +9 -4
  120. package/lib/template/list-view/list-view.component.scss +21 -21
  121. package/lib/template/list-view/list-view.component.ts +154 -84
  122. package/lib/template/list-view/utils.ts +25 -2
  123. package/lib/template/object-page/object-page.component.html +1 -0
  124. package/lib/template/object-page/object-page.component.scss +0 -0
  125. package/lib/template/object-page/object-page.component.spec.ts +22 -0
  126. package/lib/template/object-page/object-page.component.ts +14 -0
  127. package/lib/template/one-column-tab/one-column-tab.component.scss +1 -1
  128. package/lib/template/repeating-structures/repeating-structures.component.ts +0 -1
  129. package/lib/template/self-service-case-view/self-service-case-view.component.html +80 -0
  130. package/lib/template/self-service-case-view/self-service-case-view.component.scss +124 -0
  131. package/lib/template/self-service-case-view/self-service-case-view.component.spec.ts +24 -0
  132. package/lib/template/self-service-case-view/self-service-case-view.component.ts +216 -0
  133. package/lib/template/simple-table/simple-table.component.ts +0 -1
  134. package/lib/template/simple-table-manual/helpers.ts +2 -2
  135. package/lib/template/simple-table-manual/simple-table-manual.component.html +4 -4
  136. package/lib/template/simple-table-manual/simple-table-manual.component.scss +4 -14
  137. package/lib/template/simple-table-manual/simple-table-manual.component.ts +8 -4
  138. package/lib/template/single-reference-readonly/single-reference-readonly.component.html +4 -1
  139. package/lib/template/single-reference-readonly/single-reference-readonly.component.scss +21 -0
  140. package/lib/template/single-reference-readonly/single-reference-readonly.component.ts +104 -3
  141. package/lib/template/utils.ts +42 -0
  142. package/lib/template/wss-nav-bar/wss-nav-bar.component.html +5 -4
  143. package/lib/template/wss-nav-bar/wss-nav-bar.component.scss +2 -8
  144. package/lib/template/wss-nav-bar/wss-nav-bar.component.ts +1 -8
  145. package/lib/widget/app-announcement/app-announcement.component.html +1 -2
  146. package/lib/widget/app-announcement/app-announcement.component.scss +2 -2
  147. package/lib/widget/attachment/Attachment.types.ts +92 -0
  148. package/lib/widget/attachment/AttachmentUtils.ts +287 -0
  149. package/lib/widget/attachment/attachment.component.html +3 -3
  150. package/lib/widget/attachment/attachment.component.scss +2 -5
  151. package/lib/widget/attachment/attachment.component.ts +255 -254
  152. package/lib/widget/feed-container/feed-container.component.scss +3 -9
  153. package/lib/widget/feed-container/feed-container.component.ts +2 -2
  154. package/lib/widget/file-utility/file-utility.component.html +3 -3
  155. package/lib/widget/file-utility/file-utility.component.scss +5 -16
  156. package/lib/widget/list-utility/list-utility.component.scss +3 -5
  157. package/lib/widget/todo/todo.component.html +8 -5
  158. package/lib/widget/todo/todo.component.scss +10 -11
  159. package/lib/widget/todo/todo.component.ts +6 -2
  160. package/package.json +1 -1
@@ -1,20 +1,32 @@
1
- import { Component, OnInit, Input, NgZone, OnDestroy, ViewChild, ElementRef } from '@angular/core';
1
+ import { Component, OnInit, Input, OnDestroy, ViewChild, ElementRef } from '@angular/core';
2
2
  import { FormGroup } from '@angular/forms';
3
3
  import { CommonModule } from '@angular/common';
4
4
  import { MatButtonModule } from '@angular/material/button';
5
5
  import { MatMenuModule } from '@angular/material/menu';
6
6
  import { MatIconModule } from '@angular/material/icon';
7
7
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
8
- import download from 'downloadjs';
9
8
  import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
10
9
  import { Utils } from '@pega/angular-sdk-components';
11
10
  import { PConnFieldProps } from '@pega/angular-sdk-components';
11
+ import {
12
+ clearFieldErrorMessages,
13
+ deleteAttachments,
14
+ getMappedValue,
15
+ insertAttachments,
16
+ onFileDownload,
17
+ transformAttachments,
18
+ validateFileExtension,
19
+ validateMaxSize
20
+ } from './AttachmentUtils';
21
+ import { PageInstructionOptions } from './Attachment.types';
12
22
 
13
23
  interface AttachmentProps extends Omit<PConnFieldProps, 'value'> {
14
24
  // If any, enter additional props that only exist on this component
15
25
  value: any;
16
26
  extensions: any;
17
27
  allowMultiple: boolean;
28
+ isTableFormatter: boolean;
29
+ editMode: string;
18
30
  }
19
31
 
20
32
  @Component({
@@ -31,73 +43,74 @@ export class AttachmentComponent implements OnInit, OnDestroy {
31
43
  angularPConnectData: AngularPConnectData = {};
32
44
  @ViewChild('uploader', { static: false }) fileInput: ElementRef;
33
45
 
46
+ localizationService: any;
47
+ contextName: string;
48
+ actionSequencer: any;
49
+ caseID: any;
34
50
  label$ = '';
35
51
  value$: any;
36
52
  bRequired$ = false;
37
53
  bReadonly$ = false;
38
54
  bDisabled$ = false;
39
55
  bVisible$ = true;
40
- bLoading$ = false;
41
- bShowSelector$ = true;
42
- att_categoryName: string;
43
- fileTemp: any = {};
44
- caseID: any;
45
56
  allowMultiple$ = false;
46
57
  extensions$ = '';
58
+ displayMode: string | undefined;
47
59
  status = '';
48
60
  validateMessage: string | undefined = '';
49
61
  valueRef: string;
50
- imagePath$: string;
51
62
  localizedVal = PCore.getLocaleUtils().getLocaleValue;
52
- localeCategory = 'CosmosFields';
53
- uploadMultipleFilesLabel = this.localizedVal('file_upload_text_multiple', this.localeCategory);
54
- uploadSingleFileLabel = this.localizedVal('file_upload_text_one', this.localeCategory);
63
+ uploadMultipleFilesLabel = this.localizedVal('file_upload_text_multiple', 'CosmosFields');
64
+ uploadSingleFileLabel = this.localizedVal('file_upload_text_one', 'CosmosFields');
55
65
  filesWithError: any = [];
56
66
  files: any = [];
57
- categoryName: string;
58
- displayMode: string | undefined;
59
67
  srcImg: any;
60
68
  deleteIcon: string;
61
69
  tempFilesToBeUploaded: any[];
70
+ attachments: any;
71
+ attachmentCount: number = 0;
72
+ isOldAttachment = false;
73
+ multiAttachmentsInInlineEdit: any = [];
74
+ isMultiAttachmentInInlineEditTable;
75
+ overrideLocalState = false;
76
+
62
77
  constructor(
63
78
  private angularPConnect: AngularPConnectService,
64
- private utils: Utils,
65
- private ngZone: NgZone
79
+ private utils: Utils
66
80
  ) {}
67
81
 
68
82
  ngOnInit(): void {
69
- // // First thing in initialization is registering and subscribing to the AngularPConnect service
70
- this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange);
71
- this.caseID = PCore.getStoreValue('.pyID', 'caseInfo.content', this.pConn$.getContextName());
72
83
  this.srcImg = this.utils.getImageSrc('document-doc', this.utils.getSDKStaticContentUrl());
73
84
  this.deleteIcon = this.utils.getImageSrc('trash', this.utils.getSDKStaticContentUrl());
74
- this.checkAndUpdate();
75
- this.getAttachments();
76
- }
77
85
 
78
- getAttachments() {
79
- let tempUploadedFiles = this.getCurrentAttachmentsList(this.getAttachmentKey(this.valueRef), this.pConn$.getContextName());
80
- tempUploadedFiles = tempUploadedFiles.filter(f => f.label === this.valueRef && f.delete !== true);
81
- this.files?.map(f => {
82
- return f.responseProps?.pzInsKey && !f.responseProps.pzInsKey.includes('temp')
83
- ? {
84
- ...f,
85
- props: {
86
- ...f.props,
87
- onDelete: () => this.deleteFile(f)
88
- }
89
- }
90
- : { ...f };
91
- });
92
- this.files = [...this.files, ...tempUploadedFiles];
93
- PCore.getPubSubUtils().subscribe(
94
- PCore.getConstants().PUB_SUB_EVENTS.CASE_EVENTS.ASSIGNMENT_SUBMISSION,
95
- this.resetAttachmentStoredState.bind(this),
96
- this.caseID
97
- );
98
- return () => {
99
- PCore.getPubSubUtils().unsubscribe(PCore.getConstants().PUB_SUB_EVENTS.CASE_EVENTS.ASSIGNMENT_SUBMISSION, this.caseID);
100
- };
86
+ this.localizationService = this.pConn$.getLocalizationService();
87
+ this.contextName = this.pConn$.getContextName();
88
+ this.actionSequencer = PCore.getActionsSequencer();
89
+
90
+ this.caseID = PCore.getStoreValue(`.${getMappedValue('pyID')}`, PCore.getResolvedConstantValue('caseInfo.content'), this.contextName);
91
+
92
+ this.displayMode = this.pConn$.getConfigProps().displayMode;
93
+
94
+ if (this.displayMode !== 'DISPLAY_ONLY') {
95
+ PCore.getPubSubUtils().subscribe(
96
+ PCore.getConstants().PUB_SUB_EVENTS.CASE_EVENTS.ASSIGNMENT_SUBMISSION,
97
+ () => {
98
+ this.overrideLocalState = true;
99
+ },
100
+ this.caseID
101
+ );
102
+ }
103
+
104
+ const { value } = this.pConn$.getConfigProps();
105
+ const rawValue = this.pConn$.getComponentConfig().value;
106
+ const isAttachmentAnnotationPresent = typeof rawValue === 'object' ? false : rawValue?.includes('@ATTACHMENT');
107
+ const { attachments, isOldAttachment } = isAttachmentAnnotationPresent ? value : PCore.getAttachmentUtils().prepareAttachmentData(value);
108
+ this.isOldAttachment = isOldAttachment;
109
+ this.attachments = attachments;
110
+ this.files = transformAttachments(attachments);
111
+
112
+ this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange);
113
+ this.checkAndUpdate();
101
114
  }
102
115
 
103
116
  checkAndUpdate() {
@@ -119,27 +132,14 @@ export class AttachmentComponent implements OnInit, OnDestroy {
119
132
  updateSelf() {
120
133
  const configProps: AttachmentProps = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as AttachmentProps;
121
134
  const stateProps = this.pConn$.getStateProps();
122
- const { value, label, extensions, displayMode } = configProps;
123
-
124
- if (configProps.required != null) {
125
- this.bRequired$ = this.utils.getBooleanValue(configProps.required);
126
- }
127
- if (configProps.visibility != null) {
128
- this.bVisible$ = this.utils.getBooleanValue(configProps.visibility);
129
- }
130
-
131
- // disabled
132
- if (configProps.disabled != undefined) {
133
- this.bDisabled$ = this.utils.getBooleanValue(configProps.disabled);
134
- }
135
+ const { value, label, required, visibility, disabled, readOnly, extensions, displayMode, isTableFormatter, allowMultiple, editMode } =
136
+ configProps;
135
137
 
136
- if (configProps.readOnly != null) {
137
- this.bReadonly$ = this.utils.getBooleanValue(configProps.readOnly);
138
- }
139
-
140
- if (configProps.allowMultiple != null) {
141
- this.allowMultiple$ = this.utils.getBooleanValue(configProps.allowMultiple);
142
- }
138
+ this.bRequired$ = this.utils.getBooleanValue(required);
139
+ this.bVisible$ = this.utils.getBooleanValue(visibility);
140
+ this.bDisabled$ = this.utils.getBooleanValue(disabled);
141
+ this.bReadonly$ = this.utils.getBooleanValue(readOnly);
142
+ this.allowMultiple$ = this.utils.getBooleanValue(allowMultiple);
143
143
 
144
144
  this.label$ = label;
145
145
  this.value$ = value;
@@ -149,142 +149,102 @@ export class AttachmentComponent implements OnInit, OnDestroy {
149
149
  this.extensions$ = extensions;
150
150
  this.valueRef = this.pConn$.getStateProps().value;
151
151
  this.valueRef = this.valueRef.startsWith('.') ? this.valueRef.substring(1) : this.valueRef;
152
- this.displayMode = displayMode;
153
- /* this is a temporary fix because required is supposed to be passed as a boolean and NOT as a string */
154
- let { required, disabled } = configProps;
155
- [required, disabled] = [required, disabled].map(prop => prop === true || (typeof prop === 'string' && prop === 'true'));
156
152
 
157
- this.categoryName = '';
158
- if (value && value.pyCategoryName) {
159
- this.categoryName = value.pyCategoryName;
160
- }
153
+ this.pConn$.setReferenceList(`.${this.valueRef}`);
161
154
 
162
- if (value?.pxResults && +value.pyCount > 0) {
163
- this.files = value.pxResults.map(f => this.buildFilePropsFromResponse(f));
164
- }
155
+ this.displayMode = displayMode;
156
+ this.isMultiAttachmentInInlineEditTable = isTableFormatter && allowMultiple && editMode === 'tableRows';
165
157
 
158
+ // update the attachments shown in the UI
166
159
  this.updateAttachments();
167
160
  }
168
161
 
169
- buildFilePropsFromResponse(respObj) {
170
- return {
171
- props: {
172
- meta: `${respObj.pyCategoryName}, ${respObj.pxCreateOperator}`,
173
- name: respObj.pyAttachName,
174
- icon: this.utils.getIconFromFileType(respObj.pyMimeFileExtension)
175
- },
176
- responseProps: {
177
- ...respObj
178
- }
179
- };
180
- }
181
-
182
162
  updateAttachments() {
183
- if (this.files.length > 0 && this.displayMode !== 'DISPLAY_ONLY') {
184
- const currentAttachmentList = this.getCurrentAttachmentsList(this.getAttachmentKey(this.valueRef), this.pConn$.getContextName());
185
- // block duplicate files to redux store when added 1 after another to prevent multiple duplicates being added to the case on submit
186
- const tempFiles = this.files.filter(f => currentAttachmentList.findIndex(fr => fr.ID === f.ID) === -1 && !f.inProgress && f.responseProps);
187
- const updatedAttList = [...currentAttachmentList, ...tempFiles];
188
- this.updateAttachmentState(this.pConn$, this.getAttachmentKey(this.valueRef), updatedAttList);
163
+ if (this.overrideLocalState) {
164
+ const serverFiles = transformAttachments(this.attachments);
165
+ this.overrideLocalState = false;
166
+ this.attachmentCount = this.attachments.length;
167
+ this.filesWithError = [];
168
+ this.files = serverFiles;
169
+ } else {
170
+ // Determine whether refresh call has overridden any error files in redux, push error files back to redux from local state to perform client side validation during assignment submit
171
+ const errorFiles = this.attachments.filter(attachment => attachment.props.error);
172
+ if (errorFiles.length === 0 && this.filesWithError.length > 0) {
173
+ // Check if local file state contains error files and push those to redux
174
+ const uniqueKey = getMappedValue('pzInsKey');
175
+ const transformedErrorFiles = this.filesWithError.map(errorFile => {
176
+ const filename = errorFile.props.name;
177
+ return {
178
+ [uniqueKey]: errorFile.props.id,
179
+ FileName: filename,
180
+ Category: '',
181
+ FileExtension: filename.split('.').pop() ?? filename,
182
+ error: errorFile.props.error || null
183
+ };
184
+ });
185
+ let key = '';
186
+ let updatedAttachments: any = [];
187
+ if (this.allowMultiple$ || this.isOldAttachment) {
188
+ key = this.isOldAttachment ? `${this.valueRef}.pxResults` : this.valueRef;
189
+ const existingAttachments = PCore.getStoreValue(`.${key}`, this.pConn$.getPageReference(), this.pConn$.getContextName()) || [];
190
+ updatedAttachments = [...existingAttachments, ...transformedErrorFiles];
191
+ } else {
192
+ key = this.valueRef;
193
+ updatedAttachments = transformedErrorFiles[0];
194
+ }
195
+ PCore.getStateUtils().updateState(this.pConn$.getContextName(), key, updatedAttachments, {
196
+ pageReference: this.pConn$.getPageReference(),
197
+ isArrayDeepMerge: false,
198
+ removePropertyFromChangedList: true
199
+ });
200
+ }
189
201
  }
190
202
  }
191
203
 
192
- resetAttachmentStoredState() {
193
- PCore.getStateUtils().updateState(this.pConn$?.getContextName(), this.getAttachmentKey(this.valueRef), undefined, {
194
- pageReference: 'context_data',
195
- isArrayDeepMerge: false
196
- });
197
- }
198
-
199
204
  downloadFile(fileObj: any) {
200
- PCore.getAttachmentUtils()
201
- // @ts-ignore - 3rd parameter "responseEncoding" should be optional
202
- .downloadAttachment(fileObj.pzInsKey, this.pConn$.getContextName())
203
- .then((content: any) => {
204
- const extension = fileObj.pyAttachName.split('.').pop();
205
- this.fileDownload(content.data, fileObj.pyFileName, extension);
206
- })
207
- .catch(e => {
208
- console.log(e);
209
- });
210
- }
211
-
212
- fileDownload = (data, fileName, ext) => {
213
- const file = ext ? `${fileName}.${ext}` : fileName;
214
- download(atob(data), file);
215
- };
216
-
217
- getAttachmentKey = (name = '') => (name ? `attachmentsList.${name}` : 'attachmentsList');
218
-
219
- getCurrentAttachmentsList(key, context) {
220
- return PCore.getStoreValue(`.${key}`, 'context_data', context) || [];
205
+ onFileDownload(fileObj, this.contextName);
221
206
  }
222
207
 
223
- validateMaxSize(fileObj, maxSizeInMB): boolean {
224
- const fileSize = (fileObj.size / 1048576).toFixed(2);
225
- return parseFloat(fileSize) < parseFloat(maxSizeInMB);
226
- }
227
-
228
- validateFileExtension = (fileObj, allowedExtensions) => {
229
- if (!allowedExtensions) {
230
- return true;
208
+ deleteFile(file, fileIndex: number) {
209
+ if (this.filesWithError.length > 0) {
210
+ this.filesWithError = this.filesWithError.filter(fileWithError => fileWithError.props.id !== file.props.id);
211
+ if (this.filesWithError.length === 0) {
212
+ clearFieldErrorMessages(this.pConn$);
213
+ }
231
214
  }
232
- const allowedExtensionList = allowedExtensions
233
- .toLowerCase()
234
- .split(',')
235
- .map(item => item.replaceAll('.', '').trim());
236
- const extension = fileObj.name.split('.').pop().toLowerCase();
237
- return allowedExtensionList.includes(extension);
238
- };
239
-
240
- updateAttachmentState(pConn, key, attachments) {
241
- PCore.getStateUtils().updateState(this.pConn$.getContextName(), key, attachments, {
242
- pageReference: 'context_data',
243
- isArrayDeepMerge: false
244
- });
245
- }
246
215
 
247
- deleteFile(file) {
248
- const attachmentsList: any[] = [];
249
- let currentAttachmentList = this.getCurrentAttachmentsList(this.getAttachmentKey(this.valueRef), this.pConn$.getContextName());
250
-
251
- // If file to be deleted is the one added in previous stage i.e. for which a file instance is created in server
252
- // no need to filter currentAttachmentList as we will get another entry of file in redux with delete & label
253
- // eslint-disable-next-line no-unsafe-optional-chaining
254
- if (this.value$ && this.value$?.pxResults && +this.value$?.pyCount > 0 && file.responseProps && file?.responseProps?.pzInsKey !== 'temp') {
255
- const updatedAttachments = this.files.map(f => {
256
- if (f.responseProps && f.responseProps.pzInsKey === file.responseProps.pzInsKey) {
257
- return { ...f, delete: true, label: this.valueRef };
216
+ if (file.inProgress) {
217
+ // @ts-ignore - Expected 1 arguments, but got 2.ts(2554)
218
+ PCore.getAttachmentUtils().cancelRequest(file.props.id, this.contextName);
219
+ this.actionSequencer.deRegisterBlockingAction(this.contextName).catch(() => {});
220
+ this.files = this.files.filter(localFile => localFile.props.id !== file.props.id);
221
+ } else {
222
+ deleteAttachments([file], this.pConn$, this.multiAttachmentsInInlineEdit, {
223
+ allowMultiple: this.allowMultiple$,
224
+ isOldAttachment: this.isOldAttachment,
225
+ isMultiAttachmentInInlineEditTable: this.isMultiAttachmentInInlineEditTable,
226
+ attachmentCount: this.attachmentCount,
227
+ deleteIndex: fileIndex
228
+ } as any);
229
+
230
+ // Filter out without deleted file and reset the file indexes
231
+ let tempLocalFiles = [...this.files];
232
+ tempLocalFiles = tempLocalFiles.filter(localFile => localFile.props.id !== file.props.id);
233
+ tempLocalFiles.forEach(localFile => {
234
+ if (!localFile.props.error && !file.props.error) {
235
+ const updatedDeleteIndex =
236
+ localFile.responseProps.deleteIndex > fileIndex ? localFile.responseProps.deleteIndex - 1 : localFile.responseProps.deleteIndex;
237
+
238
+ localFile.responseProps.deleteIndex = updatedDeleteIndex;
258
239
  }
259
- return f;
260
240
  });
261
-
262
- // updating the redux store to help form-handler in passing the data to delete the file from server
263
- this.updateAttachmentState(this.pConn$, this.getAttachmentKey(this.valueRef), [...updatedAttachments]);
264
- const newlyAddedFiles = this.files.filter(f => !!f.ID);
265
- const filesPostDelete = this.files.filter(
266
- f => f.responseProps?.pzInsKey !== 'temp' && f.responseProps?.pzInsKey !== file.responseProps?.pzInsKey
267
- );
268
- this.files = [...filesPostDelete, ...newlyAddedFiles];
269
- } // if the file being deleted is the added in this stage i.e. whose data is not yet created in server
270
- else {
271
- // filter newly added files in this stage, later the updated current stage files will be added to redux once files state is updated
272
- currentAttachmentList = currentAttachmentList.filter(f => f.ID !== file.ID);
273
- this.files = this.files.filter(f => f.ID !== file.ID);
274
-
275
- this.updateAttachmentState(this.pConn$, this.getAttachmentKey(this.valueRef), [...currentAttachmentList, ...attachmentsList]);
276
- if (file.inProgress) {
277
- // @ts-ignore - 3rd parameter "responseEncoding" should be optional
278
- PCore.getAttachmentUtils().cancelRequest(file.ID, this.pConn$.getContextName());
241
+ this.files = tempLocalFiles;
242
+ if (!file.props.error) {
243
+ this.attachmentCount -= 1;
279
244
  }
280
245
  }
281
246
 
282
- this.filesWithError = this.filesWithError?.filter(f => f.ID !== file.ID);
283
- if (this.filesWithError.length === 0) {
284
- this.clearFieldErrorMessages();
285
- }
286
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
287
- this.fileInput && this.fileInput.nativeElement.value ? null : '';
247
+ this.fileInput.nativeElement.value = '';
288
248
  }
289
249
 
290
250
  onFileAdded(event) {
@@ -294,102 +254,121 @@ export class AttachmentComponent implements OnInit, OnDestroy {
294
254
  this.tempFilesToBeUploaded = [
295
255
  ...addedFiles.map((f: any, index) => {
296
256
  f.ID = `${new Date().getTime()}I${index}`;
297
- f.inProgress = true;
298
257
  f.props = {
299
258
  type: f.type,
300
259
  name: f.name,
260
+ id: f.ID,
261
+ format: f.name.split('.').pop(),
301
262
  icon: this.utils.getIconFromFileType(f.type),
302
- onDelete: () => this.deleteFile(f)
263
+ thumbnail: window.URL.createObjectURL(f)
303
264
  };
304
- if (!this.validateMaxSize(f, maxAttachmentSize)) {
265
+
266
+ if (!validateMaxSize(f, maxAttachmentSize)) {
305
267
  f.props.error = true;
306
- f.inProgress = false;
307
- f.props.meta = this.pConn$.getLocalizedValue(`File is too big. Max allowed size is ${maxAttachmentSize}MB.`, '', '');
308
- } else if (!this.validateFileExtension(f, this.extensions$)) {
268
+ f.props.meta = this.localizationService.getLocalizedText(`File is too big. Max allowed size is ${maxAttachmentSize}MB.`);
269
+ } else if (!validateFileExtension(f, this.extensions$)) {
309
270
  f.props.error = true;
310
- f.inProgress = false;
311
- f.props.meta = `${this.pConn$.getLocalizedValue(
312
- 'File has invalid extension. Allowed extensions are:',
313
- '',
271
+ f.props.meta = `${this.localizationService.getLocalizedText('File has invalid extension. Allowed extensions are:')} ${this.extensions$.replaceAll(
272
+ '.',
314
273
  ''
315
- )} ${this.extensions$.replaceAll('.', '')}`;
274
+ )}`;
316
275
  }
276
+
317
277
  if (f.props.error) {
318
- const fieldName = this.pConn$.getStateProps().value;
319
- const context = this.pConn$.getContextName();
278
+ const fieldName = (this.pConn$.getStateProps() as any).value;
320
279
  PCore.getMessageManager().addMessages({
321
280
  messages: [
322
281
  {
323
282
  type: 'error',
324
- message: this.pConn$.getLocalizedValue('Error with one or more files', '', '')
283
+ message: this.localizationService.getLocalizedText('Error with one or more files')
325
284
  }
326
285
  ],
327
286
  property: fieldName,
328
287
  pageReference: this.pConn$.getPageReference(),
329
- context
288
+ context: this.contextName
330
289
  });
331
290
  }
332
291
  return f;
333
292
  })
334
293
  ];
294
+
335
295
  const tempFilesWithError = this.tempFilesToBeUploaded.filter(f => f.props.error);
336
296
  if (tempFilesWithError.length > 0) {
337
- this.filesWithError = tempFilesWithError;
297
+ this.filesWithError = [...this.filesWithError, ...tempFilesWithError];
298
+
299
+ insertAttachments(tempFilesWithError, this.pConn$, this.multiAttachmentsInInlineEdit, {
300
+ allowMultiple: this.allowMultiple$,
301
+ isOldAttachment: this.isOldAttachment,
302
+ isMultiAttachmentInInlineEditTable: this.isMultiAttachmentInInlineEditTable,
303
+ attachmentCount: this.attachmentCount
304
+ } as PageInstructionOptions);
338
305
  }
306
+
339
307
  if (!this.allowMultiple$) {
340
308
  this.files = [...this.tempFilesToBeUploaded];
341
309
  } else {
342
310
  this.files = [...this.files, ...this.tempFilesToBeUploaded];
343
311
  }
344
- this.uploadFiles();
312
+
313
+ this.actionSequencer.registerBlockingAction(this.contextName).then(() => {
314
+ this.uploadFiles();
315
+ });
316
+ }
317
+
318
+ onUploadProgress(id, ev) {
319
+ const progress = Math.floor((ev.loaded / ev.total) * 100);
320
+ this.files = this.files.map(localFile => {
321
+ if (localFile.props?.id === id) {
322
+ localFile.inProgress = true;
323
+ localFile.props.progress = progress;
324
+ }
325
+ return localFile;
326
+ });
345
327
  }
346
328
 
347
- clearFieldErrorMessages() {
348
- const fieldName = this.pConn$.getStateProps().value;
349
- const context = this.pConn$.getContextName();
350
- PCore.getMessageManager().clearMessages({
351
- type: PCore.getConstants().MESSAGES.MESSAGES_TYPE_ERROR,
329
+ populateErrorAndUpdateRedux(file) {
330
+ const fieldName = (this.pConn$.getStateProps() as any).value;
331
+ // set errors to property to block submit even on errors in file upload
332
+ PCore.getMessageManager().addMessages({
333
+ messages: [
334
+ {
335
+ type: 'error',
336
+ message: this.localizationService.getLocalizedText('Error with one or more files')
337
+ }
338
+ ],
352
339
  property: fieldName,
353
340
  pageReference: this.pConn$.getPageReference(),
354
- context
341
+ context: this.contextName
355
342
  });
343
+ insertAttachments([file], this.pConn$, this.multiAttachmentsInInlineEdit, {
344
+ allowMultiple: this.allowMultiple$,
345
+ isOldAttachment: this.isOldAttachment,
346
+ isMultiAttachmentInInlineEditTable: this.isMultiAttachmentInInlineEditTable,
347
+ attachmentCount: this.attachmentCount
348
+ } as any);
356
349
  }
357
350
 
358
- onUploadProgress() {}
359
-
360
- errorHandler(isFetchCanceled, attachedFile) {
351
+ errorHandler(isFetchCanceled, file) {
361
352
  return error => {
362
353
  if (!isFetchCanceled(error)) {
363
- let uploadFailMsg = this.pConn$.getLocalizedValue('Something went wrong', '', '');
354
+ let uploadFailMsg = this.localizationService.getLocalizedText('Something went wrong');
364
355
  if (error.response && error.response.data && error.response.data.errorDetails) {
365
- uploadFailMsg = this.pConn$.getLocalizedValue(error.response.data.errorDetails[0].localizedValue, '', '');
356
+ uploadFailMsg = this.localizationService.getLocalizedText(error.response.data.errorDetails[0].localizedValue);
366
357
  }
367
358
 
368
- this.files.map(f => {
369
- if (f.ID === attachedFile.ID) {
370
- f.props.meta = uploadFailMsg;
371
- f.props.error = true;
372
- f.props.onDelete = () => this.deleteFile(f);
373
- f.props.icon = this.utils.getIconFromFileType(f.type);
374
- f.props.name = this.pConn$.getLocalizedValue('Unable to upload file', '', '');
375
- f.inProgress = false;
376
- const fieldName = this.pConn$.getStateProps().value;
377
- const context = this.pConn$.getContextName();
378
- // set errors to property to block submit even on errors in file upload
379
- PCore.getMessageManager().addMessages({
380
- messages: [
381
- {
382
- type: 'error',
383
- message: this.pConn$.getLocalizedValue('Error with one or more files', '', '')
384
- }
385
- ],
386
- property: fieldName,
387
- pageReference: this.pConn$.getPageReference(),
388
- context
389
- });
390
- delete f.props.progress;
359
+ this.files = this.files.map(localFile => {
360
+ if (localFile.props.id === file.props.id) {
361
+ localFile.props.meta = uploadFailMsg;
362
+ localFile.props.error = true;
363
+ localFile.props.icon = this.utils.getIconFromFileType(localFile.type);
364
+ localFile.props.name = this.localizationService.getLocalizedText('Unable to upload file');
365
+ localFile.inProgress = false;
366
+ delete localFile.props.progress;
367
+ this.filesWithError.push(localFile);
368
+
369
+ this.populateErrorAndUpdateRedux(localFile);
391
370
  }
392
- return f;
371
+ return localFile;
393
372
  });
394
373
  }
395
374
  throw error;
@@ -401,44 +380,64 @@ export class AttachmentComponent implements OnInit, OnDestroy {
401
380
  .filter(e => {
402
381
  const isFileUploaded = e.props && e.props.progress === 100;
403
382
  const fileHasError = e.props && e.props.error;
404
- const isFileUploadedinLastStep = e.responseProps && e.responseProps.pzInsKey;
405
- return !isFileUploaded && !fileHasError && !isFileUploadedinLastStep;
383
+ const isFileUploadedInLastStep = e.responseProps && e.responseProps.ID !== 'temp';
384
+ const isFileUploadInProgress = e.inProgress;
385
+ return !isFileUploadInProgress && !isFileUploaded && !fileHasError && !isFileUploadedInLastStep;
406
386
  })
407
- .map(f =>
408
- window.PCore.getAttachmentUtils().uploadAttachment(
409
- f,
410
- () => {
411
- this.onUploadProgress();
387
+ .map(file =>
388
+ PCore.getAttachmentUtils().uploadAttachment(
389
+ file,
390
+ ev => {
391
+ this.onUploadProgress(file.props.id, ev);
412
392
  },
413
393
  isFetchCanceled => {
414
- return this.errorHandler(isFetchCanceled, f);
394
+ return this.errorHandler(isFetchCanceled, file);
415
395
  },
416
- this.pConn$.getContextName()
396
+ this.contextName
417
397
  )
418
398
  );
399
+
419
400
  Promise.allSettled(filesToBeUploaded)
420
401
  .then((fileResponses: any) => {
421
402
  fileResponses = fileResponses.filter(fr => fr.status !== 'rejected'); // in case of deleting an in progress file, promise gets cancelled but still enters then block
422
403
  if (fileResponses.length > 0) {
423
- this.files.forEach(f => {
424
- const index = fileResponses.findIndex((fr: any) => fr.value.clientFileID === f.ID);
404
+ this.files = this.files.map(localFile => {
405
+ // if attach field has multiple files & in bw any error files are present
406
+ // Example : files = [properFile1, errFile, errFile, properFile2]
407
+ // indexes for delete & preview should be for files [properFile1, properFile2] which is [1,2]
408
+ const index = fileResponses.findIndex(fileResponse => fileResponse.value.clientFileID === localFile.props.id);
425
409
  if (index >= 0) {
426
- f.props.meta = this.pConn$.getLocalizedValue('Uploaded successfully', '', '');
427
- f.props.progress = 100;
428
- f.inProgress = false;
429
- f.handle = fileResponses[index].value.ID;
430
- f.label = this.valueRef;
431
- f.category = this.categoryName;
432
- f.responseProps = {
410
+ fileResponses[index].value.thumbnail = localFile.props.thumbnail;
411
+ localFile.inProgress = false;
412
+ localFile.ID = fileResponses[index].value.ID;
413
+ localFile.props.meta = this.localizationService.getLocalizedText('Uploaded successfully');
414
+ localFile.props.progress = 100;
415
+ localFile.handle = fileResponses[index].value.ID;
416
+ localFile.label = this.valueRef;
417
+ localFile.responseProps = {
433
418
  pzInsKey: 'temp',
434
- pyAttachName: f.props.name
419
+ pyAttachName: localFile.props.name
435
420
  };
436
421
  }
422
+
423
+ return localFile;
437
424
  });
438
- this.updateAttachments();
425
+
426
+ insertAttachments(fileResponses, this.pConn$, this.multiAttachmentsInInlineEdit, {
427
+ allowMultiple: this.allowMultiple$,
428
+ isOldAttachment: this.isOldAttachment,
429
+ isMultiAttachmentInInlineEditTable: this.isMultiAttachmentInInlineEditTable,
430
+ attachmentCount: this.attachmentCount,
431
+ insert: true
432
+ } as any);
433
+
434
+ this.attachmentCount += fileResponses.length;
435
+
439
436
  if (this.filesWithError?.length === 0) {
440
- this.clearFieldErrorMessages();
437
+ clearFieldErrorMessages(this.pConn$);
441
438
  }
439
+
440
+ this.actionSequencer.deRegisterBlockingAction(this.contextName).catch(() => {});
442
441
  }
443
442
  })
444
443
  .catch(error => {
@@ -451,6 +450,8 @@ export class AttachmentComponent implements OnInit, OnDestroy {
451
450
  this.angularPConnectData.unsubscribeFn();
452
451
  }
453
452
 
454
- PCore.getPubSubUtils().unsubscribe(PCore.getConstants().PUB_SUB_EVENTS.CASE_EVENTS.ASSIGNMENT_SUBMISSION, this.caseID);
453
+ if (this.displayMode !== 'DISPLAY_ONLY') {
454
+ PCore.getPubSubUtils().unsubscribe(PCore.getConstants().PUB_SUB_EVENTS.CASE_EVENTS.ASSIGNMENT_SUBMISSION, this.caseID);
455
+ }
455
456
  }
456
457
  }