@pega/angular-sdk-overrides 25.1.12 → 26.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 (168) hide show
  1. package/lib/designSystemExtension/alert/alert.component.html +4 -1
  2. package/lib/designSystemExtension/alert/alert.component.scss +9 -10
  3. package/lib/designSystemExtension/alert/alert.component.ts +6 -2
  4. package/lib/designSystemExtension/field-group/field-group.component.ts +11 -3
  5. package/lib/designSystemExtension/material-case-summary/material-case-summary.component.html +51 -36
  6. package/lib/designSystemExtension/material-case-summary/material-case-summary.component.scss +12 -0
  7. package/lib/designSystemExtension/material-case-summary/material-case-summary.component.ts +11 -0
  8. package/lib/designSystemExtension/operator/operator.component.html +5 -3
  9. package/lib/designSystemExtension/operator/operator.component.scss +7 -0
  10. package/lib/designSystemExtension/operator/operator.component.ts +2 -1
  11. package/lib/designSystemExtension/rich-text-editor/rich-text-editor.component.html +100 -10
  12. package/lib/designSystemExtension/rich-text-editor/rich-text-editor.component.scss +141 -1
  13. package/lib/designSystemExtension/rich-text-editor/rich-text-editor.component.spec.ts +1 -1
  14. package/lib/designSystemExtension/rich-text-editor/rich-text-editor.component.ts +240 -72
  15. package/lib/field/auto-complete/auto-complete.component.html +46 -5
  16. package/lib/field/auto-complete/auto-complete.component.scss +92 -0
  17. package/lib/field/auto-complete/auto-complete.component.ts +350 -23
  18. package/lib/field/cancel-alert/cancel-alert.component.ts +38 -15
  19. package/lib/field/check-box/check-box.component.html +8 -6
  20. package/lib/field/check-box/check-box.component.ts +9 -2
  21. package/lib/field/currency/currency.component.html +2 -1
  22. package/lib/field/currency/currency.component.ts +10 -1
  23. package/lib/field/date/date.component.html +2 -1
  24. package/lib/field/date/date.component.ts +2 -0
  25. package/lib/field/date-time/date-time.component.html +2 -1
  26. package/lib/field/date-time/date-time.component.scss +46 -40
  27. package/lib/field/date-time/date-time.component.ts +29 -0
  28. package/lib/field/decimal/decimal.component.html +2 -1
  29. package/lib/field/decimal/decimal.component.ts +2 -0
  30. package/lib/field/dropdown/dropdown.component.html +4 -1
  31. package/lib/field/dropdown/dropdown.component.ts +18 -19
  32. package/lib/field/email/email.component.html +2 -1
  33. package/lib/field/email/email.component.ts +2 -2
  34. package/lib/field/embedded-data-multi/embedded-data-multi.component.html +3 -0
  35. package/lib/field/embedded-data-multi/embedded-data-multi.component.scss +0 -0
  36. package/lib/field/embedded-data-multi/embedded-data-multi.component.ts +173 -0
  37. package/lib/field/field.base.ts +27 -1
  38. package/lib/field/group/group.component.html +1 -1
  39. package/lib/field/group/group.component.ts +16 -7
  40. package/lib/field/integer/integer.component.html +2 -1
  41. package/lib/field/integer/integer.component.ts +4 -2
  42. package/lib/field/location/location.component.html +2 -1
  43. package/lib/field/location/location.component.ts +3 -1
  44. package/lib/field/multiselect/multiselect.component.html +1 -1
  45. package/lib/field/multiselect/multiselect.component.ts +23 -4
  46. package/lib/field/multiselect/utils.ts +5 -3
  47. package/lib/field/object-reference/object-reference.component.html +30 -15
  48. package/lib/field/object-reference/object-reference.component.ts +818 -94
  49. package/lib/field/percentage/percentage.component.html +2 -1
  50. package/lib/field/percentage/percentage.component.ts +10 -1
  51. package/lib/field/phone/phone.component.html +2 -1
  52. package/lib/field/phone/phone.component.ts +2 -1
  53. package/lib/field/radio-buttons/radio-buttons.component.html +2 -1
  54. package/lib/field/radio-buttons/radio-buttons.component.ts +10 -1
  55. package/lib/field/rich-text/rich-text.component.scss +1 -166
  56. package/lib/field/rich-text/rich-text.component.spec.ts +1 -1
  57. package/lib/field/rich-text/rich-text.component.ts +1 -1
  58. package/lib/field/selectable-card/selectable-card.component.html +1 -0
  59. package/lib/field/selectable-card/selectable-card.component.ts +31 -16
  60. package/lib/field/semantic-link/semantic-link.component.html +1 -1
  61. package/lib/field/semantic-link/semantic-link.component.scss +4 -0
  62. package/lib/field/semantic-link/semantic-link.component.ts +13 -7
  63. package/lib/field/text-area/text-area.component.html +2 -1
  64. package/lib/field/text-area/text-area.component.ts +2 -1
  65. package/lib/field/text-input/text-input.component.html +2 -1
  66. package/lib/field/text-input/text-input.component.ts +2 -1
  67. package/lib/field/time/time.component.html +2 -1
  68. package/lib/field/time/time.component.ts +2 -1
  69. package/lib/field/url/url.component.html +2 -1
  70. package/lib/field/url/url.component.ts +2 -1
  71. package/lib/field/user-reference/user-reference.component.html +4 -2
  72. package/lib/field/user-reference/user-reference.component.ts +11 -6
  73. package/lib/infra/Containers/flow-container/flow-container.component.html +2 -2
  74. package/lib/infra/Containers/flow-container/flow-container.component.ts +34 -42
  75. package/lib/infra/Containers/modal-view-container/data-view-action-buttons/data-view-action-buttons.component.html +12 -0
  76. package/lib/infra/Containers/modal-view-container/data-view-action-buttons/data-view-action-buttons.component.spec.ts +130 -0
  77. package/lib/infra/Containers/modal-view-container/data-view-action-buttons/data-view-action-buttons.component.ts +77 -0
  78. package/lib/infra/Containers/modal-view-container/modal-view-container.component.html +35 -8
  79. package/lib/infra/Containers/modal-view-container/modal-view-container.component.ts +185 -196
  80. package/lib/infra/Containers/view-container/view-container.component.html +1 -1
  81. package/lib/infra/Containers/view-container/view-container.component.ts +36 -43
  82. package/lib/infra/assignment/assignment.component.html +2 -1
  83. package/lib/infra/assignment/assignment.component.ts +44 -22
  84. package/lib/infra/assignment-card/assignment-card.component.html +1 -0
  85. package/lib/infra/assignment-card/assignment-card.component.ts +2 -8
  86. package/lib/infra/defer-load/defer-load.component.ts +7 -5
  87. package/lib/infra/multi-step/multi-step.component.html +25 -33
  88. package/lib/infra/multi-step/multi-step.component.scss +67 -125
  89. package/lib/infra/multi-step/multi-step.component.ts +11 -0
  90. package/lib/infra/navbar/navbar.component.ts +33 -36
  91. package/lib/infra/reference/reference.component.html +7 -1
  92. package/lib/infra/reference/reference.component.ts +63 -109
  93. package/lib/infra/region/region.component.ts +1 -3
  94. package/lib/infra/root-container/root-container.component.html +1 -0
  95. package/lib/infra/root-container/root-container.component.ts +34 -42
  96. package/lib/infra/view/view.component.ts +22 -46
  97. package/lib/template/advanced-search/advanced-search.component.ts +0 -1
  98. package/lib/template/advanced-search/search-groups/search-groups.component.ts +2 -3
  99. package/lib/template/app-shell/app-shell.component.ts +13 -13
  100. package/lib/template/banner-page/banner-page.component.ts +1 -2
  101. package/lib/template/base/details-template-base.ts +41 -14
  102. package/lib/template/base/form-template-base.ts +0 -2
  103. package/lib/template/case-summary/case-summary.component.ts +15 -7
  104. package/lib/template/case-view/case-view.component.html +14 -2
  105. package/lib/template/case-view/case-view.component.spec.ts +119 -10
  106. package/lib/template/case-view/case-view.component.ts +52 -3
  107. package/lib/template/data-reference/data-reference.component.ts +29 -22
  108. package/lib/template/data-reference/search-form/search-form.component.html +1 -1
  109. package/lib/template/data-reference/search-form/search-form.component.ts +9 -1
  110. package/lib/template/data-reference/search-form/tabsData.ts +0 -1
  111. package/lib/template/default-form/default-form.component.html +20 -4
  112. package/lib/template/default-form/default-form.component.ts +14 -5
  113. package/lib/template/default-page/default-page.component.ts +1 -2
  114. package/lib/template/details/details.component.html +23 -3
  115. package/lib/template/details/details.component.scss +9 -2
  116. package/lib/template/details/details.component.ts +3 -70
  117. package/lib/template/details-narrow-wide/details-narrow-wide.component.html +21 -2
  118. package/lib/template/details-narrow-wide/details-narrow-wide.component.scss +8 -1
  119. package/lib/template/details-narrow-wide/details-narrow-wide.component.ts +3 -39
  120. package/lib/template/details-one-column/details-one-column.component.html +23 -1
  121. package/lib/template/details-one-column/details-one-column.component.scss +14 -0
  122. package/lib/template/details-one-column/details-one-column.component.ts +3 -40
  123. package/lib/template/details-three-column/details-three-column.component.html +21 -2
  124. package/lib/template/details-three-column/details-three-column.component.scss +8 -1
  125. package/lib/template/details-three-column/details-three-column.component.ts +3 -48
  126. package/lib/template/details-two-column/details-two-column.component.html +21 -2
  127. package/lib/template/details-two-column/details-two-column.component.scss +8 -1
  128. package/lib/template/details-two-column/details-two-column.component.ts +3 -46
  129. package/lib/template/details-wide-narrow/details-wide-narrow.component.html +21 -2
  130. package/lib/template/details-wide-narrow/details-wide-narrow.component.scss +8 -1
  131. package/lib/template/details-wide-narrow/details-wide-narrow.component.ts +3 -43
  132. package/lib/template/dynamic-tabs/dynamic-tabs.component.html +1 -0
  133. package/lib/template/field-group-template/field-group-template.component.ts +19 -6
  134. package/lib/template/field-value-list/field-value-list.component.scss +17 -0
  135. package/lib/template/inline-dashboard-page/inline-dashboard-page.component.ts +2 -10
  136. package/lib/template/list-view/list-view.component.ts +47 -11
  137. package/lib/template/one-column/one-column.component.html +3 -0
  138. package/lib/template/one-column-tab/one-column-tab.component.html +1 -0
  139. package/lib/template/page/page.component.html +1 -0
  140. package/lib/template/self-service-case-view/self-service-case-view.component.html +13 -1
  141. package/lib/template/self-service-case-view/self-service-case-view.component.spec.ts +96 -11
  142. package/lib/template/self-service-case-view/self-service-case-view.component.ts +52 -3
  143. package/lib/template/simple-table/simple-table.component.ts +11 -1
  144. package/lib/template/simple-table-manual/helpers.ts +84 -16
  145. package/lib/template/simple-table-manual/simple-table-manual.component.html +30 -14
  146. package/lib/template/simple-table-manual/simple-table-manual.component.scss +8 -2
  147. package/lib/template/simple-table-manual/simple-table-manual.component.ts +142 -46
  148. package/lib/template/single-reference-readonly/single-reference-readonly.component.html +0 -0
  149. package/lib/template/single-reference-readonly/single-reference-readonly.component.scss +2 -3
  150. package/lib/template/single-reference-readonly/single-reference-readonly.component.ts +7 -8
  151. package/lib/template/wide-narrow-page/wide-narrow-page.component.ts +0 -3
  152. package/lib/template/wss-nav-bar/wss-nav-bar.component.ts +19 -21
  153. package/lib/widget/attachment/AttachmentUtils.ts +19 -11
  154. package/lib/widget/attachment/attachment.component.html +16 -6
  155. package/lib/widget/attachment/attachment.component.ts +14 -4
  156. package/lib/widget/case-history/case-history.component.ts +6 -2
  157. package/lib/widget/feed-container/feed-container.component.ts +1 -199
  158. package/lib/widget/file-utility/file-utility.component.ts +26 -30
  159. package/lib/widget/todo/todo.component.ts +7 -2
  160. package/package.json +2 -2
  161. package/lib/designSystemExtension/material-details/material-details.component.html +0 -40
  162. package/lib/designSystemExtension/material-details/material-details.component.scss +0 -116
  163. package/lib/designSystemExtension/material-details/material-details.component.spec.ts +0 -24
  164. package/lib/designSystemExtension/material-details/material-details.component.ts +0 -31
  165. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.html +0 -29
  166. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.scss +0 -34
  167. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.spec.ts +0 -22
  168. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.ts +0 -37
@@ -1,18 +1,32 @@
1
- import { Component, OnInit, Input, Output, EventEmitter, NgZone, forwardRef, OnDestroy } from '@angular/core';
1
+ import { ChangeDetectorRef, Component, OnInit, Input, Output, EventEmitter, forwardRef, OnDestroy } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { FormBuilder, FormGroup } from '@angular/forms';
4
- import isEqual from 'fast-deep-equal';
5
4
  import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
6
5
  import { ProgressSpinnerService } from '@pega/angular-sdk-components';
6
+ import { BannerService } from '@pega/angular-sdk-components';
7
7
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
8
- import { getBanners } from '@pega/angular-sdk-components';
9
- import { ReferenceComponent } from '@pega/angular-sdk-components';
10
8
 
11
9
  /**
12
10
  * WARNING: This file is part of the infrastructure component responsible for working with Redux and managing the creation and update of Redux containers and PConnect.
13
11
  * You may override Material components within this component if needed, but do not modify any container-related logic. Changing this logic can lead to unexpected behavior.
14
12
  */
15
13
 
14
+ // One entry per open modal — supports stacking (e.g. "Create new" opened from within another modal)
15
+ interface ModalEntry {
16
+ key: string;
17
+ title: string;
18
+ createdViewPConn$: any;
19
+ arChildren$: any[];
20
+ isMultiRecordData: boolean;
21
+ isDataObjectModal: boolean;
22
+ dataRecordKeys: string;
23
+ dataObjectActionID: string;
24
+ dataObjectAction: string;
25
+ dataObjectClassId: string;
26
+ context: string;
27
+ updateToken: number;
28
+ }
29
+
16
30
  @Component({
17
31
  selector: 'app-modal-view-container',
18
32
  templateUrl: './modal-view-container.component.html',
@@ -28,41 +42,33 @@ export class ModalViewContainerComponent implements OnInit, OnDestroy {
28
42
  // Used with AngularPConnect
29
43
  angularPConnectData: AngularPConnectData = {};
30
44
 
31
- arChildren$: any[];
32
45
  stateProps$: object;
33
- banners: any;
34
- templateName$: string;
35
- buildName$: string;
36
- context$: string;
37
- title$ = '';
38
- bShowModal$ = false;
39
- itemKey$: string;
40
46
  formGroup$: FormGroup;
41
- oCaseInfo: object = {};
42
-
43
- // for causing a change on assignment
44
- updateToken$ = 0;
45
47
 
46
48
  routingInfoRef: any = {};
47
49
 
48
- // created object is now a View with a Template
49
- // Use its PConnect to render the CaseView; DON'T replace this.pConn$
50
- createdViewPConn$: any;
50
+ // Stack of open modals — supports one modal opening another (e.g. "Create new" from within a modal).
51
+ // Keyed the same as PCore's routingInfo.items so open/update/close can be derived from accessedOrder.
52
+ modalStack: ModalEntry[] = [];
53
+ private modalCollection: Record<string, object> = {};
51
54
 
52
55
  bSubscribed = false;
53
56
  cancelPConn$?: typeof PConnect;
57
+ cancelHideDelete$: boolean;
58
+ cancelIsDataObject$: boolean;
59
+ cancelSkipReleaseLockRequest$: any;
54
60
  bShowCancelAlert$ = false;
55
61
  bAlertState: boolean;
56
62
  localizedVal: Function;
57
63
  localeCategory = 'Data Object';
58
- isMultiRecord = false;
59
64
  actionsDialog = false;
60
65
 
61
66
  constructor(
62
67
  private angularPConnect: AngularPConnectService,
63
- private ngZone: NgZone,
68
+ private cdRef: ChangeDetectorRef,
64
69
  private psService: ProgressSpinnerService,
65
- private fb: FormBuilder
70
+ private fb: FormBuilder,
71
+ public bannerService: BannerService
66
72
  ) {
67
73
  // create the formGroup
68
74
  this.formGroup$ = fb.group({ hideRequired: false });
@@ -72,22 +78,12 @@ export class ModalViewContainerComponent implements OnInit, OnDestroy {
72
78
  // First thing in initialization is registering and subscribing to the AngularPConnect service
73
79
  this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange);
74
80
 
75
- const baseContext = this.pConn$.getContextName();
76
- const acName = this.pConn$.getContainerName();
77
-
78
- // for now, in general this should be overridden by updateSelf(), and not be blank
79
- if (this.itemKey$ === '') {
80
- this.itemKey$ = baseContext.concat('/').concat(acName);
81
- }
82
-
83
81
  const containerMgr = this.pConn$.getContainerManager();
84
82
 
85
83
  containerMgr.initializeContainers({
86
84
  type: 'multiple'
87
85
  });
88
86
 
89
- // const { CONTAINER_TYPE, PUB_SUB_EVENTS } = PCore.getConstants();
90
-
91
87
  this.angularPConnect.shouldComponentUpdate(this);
92
88
  this.localizedVal = PCore.getLocaleUtils().getLocaleValue;
93
89
  }
@@ -115,10 +111,6 @@ export class ModalViewContainerComponent implements OnInit, OnDestroy {
115
111
  // ONLY call updateSelf when the component should update
116
112
  if (bUpdateSelf) {
117
113
  this.updateSelf();
118
- } else if (this.bShowModal$) {
119
- // right now onlu get one updated when initial diaplay. So, once modal is up
120
- // let fall through and do a check with "compareCaseInfoIsDifferent" until fixed
121
- // this.updateSelf();
122
114
  }
123
115
  }
124
116
 
@@ -135,144 +127,102 @@ export class ModalViewContainerComponent implements OnInit, OnDestroy {
135
127
  } catch (ex) {
136
128
  console.log(ex);
137
129
  }
138
- // const configProps = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps());
139
130
  this.stateProps$ = this.pConn$.getStateProps();
140
- this.banners = this.getBanners();
141
131
 
142
- if (!loadingInfo) {
143
- // turn off spinner
144
- // this.psService.sendMessage(false);
132
+ if (!routingInfo || loadingInfo) {
133
+ return;
145
134
  }
146
135
 
147
- if (routingInfo && !loadingInfo /* && this.bUpdate */) {
148
- const currentOrder = routingInfo.accessedOrder;
136
+ const { accessedOrder, type } = routingInfo;
149
137
 
150
- if (undefined == currentOrder) {
151
- return;
152
- }
153
-
154
- const currentItems = routingInfo.items;
155
-
156
- const { key, latestItem } = this.getKeyAndLatestItem(routingInfo);
157
-
158
- if (currentOrder.length > 0) {
159
- if (currentItems[key] && currentItems[key].view && Object.keys(currentItems[key].view).length > 0) {
160
- const currentItem = currentItems[key];
161
- const rootView = currentItem.view;
162
- const { context } = rootView.config;
163
- const config: any = { meta: rootView };
164
- config.options = {
165
- context: currentItem.context,
166
- hasForm: true,
167
- pageReference: context || this.pConn$.getPageReference()
168
- };
169
-
170
- if (!this.bSubscribed) {
171
- this.bSubscribed = true;
172
- const { PUB_SUB_EVENTS } = PCore.getConstants();
173
- PCore.getPubSubUtils().subscribe(
174
- PUB_SUB_EVENTS.EVENT_SHOW_CANCEL_ALERT,
175
- payload => {
176
- this.showAlert(payload);
177
- },
178
- PUB_SUB_EVENTS.EVENT_SHOW_CANCEL_ALERT
179
- );
180
- }
181
-
182
- // let configObject = PCore.createPConnect(config);
183
-
184
- // THIS is where the ViewContainer creates a View
185
- // The config has meta.config.type = "view"
186
- this.createView(routingInfo, currentItem, latestItem, key);
187
- }
188
- } else {
189
- this.hideModal();
190
- }
138
+ if (undefined == accessedOrder) {
139
+ return;
191
140
  }
192
- }
193
141
 
194
- createView(routingInfo, currentItem, latestItem, key) {
195
- const configObject = this.getConfigObject(currentItem, null, false);
196
- const newComp = configObject?.getPConnect();
197
- // const newCompName = newComp.getComponentName();
198
- const caseInfo = newComp && newComp.getDataObject() && newComp.getDataObject().caseInfo ? newComp.getDataObject().caseInfo : null;
199
- // The metadata for pyDetails changed such that the "template": "CaseView"
200
- // is no longer a child of the created View but is in the created View's
201
- // config. So, we DON'T want to replace this.pConn$ since the created
202
- // component is a View (and not a ViewContainer). We now look for the
203
- // "template" type directly in the created component (newComp) and NOT
204
- // as a child of the newly created component.
205
- // console.log(`---> ModalViewContainer created new ${newCompName}`);
206
-
207
- // Use the newly created component (View) info but DO NOT replace
208
- // this ModalViewContainer's pConn$, etc.
209
- // Note that we're now using the newly created View's PConnect in the
210
- // ViewContainer HTML template to guide what's rendered similar to what
211
- // the Nebula/Constellation return of React.Fragment does
212
-
213
- // right now need to check caseInfo for changes, to trigger redraw, not getting
214
- // changes from angularPconnect except for first draw
215
- if (newComp && caseInfo && this.compareCaseInfoIsDifferent(caseInfo)) {
216
- this.psService.sendMessage(false);
217
-
218
- this.ngZone.run(() => {
219
- this.createdViewPConn$ = newComp;
220
- const newConfigProps = newComp.getConfigProps();
221
- this.templateName$ = 'template' in newConfigProps ? (newConfigProps.template as string) : '';
222
-
223
- const { actionName } = latestItem;
224
- const theNewCaseInfo = newComp.getCaseInfo();
225
- // const caseName = theNewCaseInfo.getName();
226
- const ID = theNewCaseInfo.getBusinessID() || theNewCaseInfo.getID();
227
-
228
- const caseTypeName = theNewCaseInfo.getCaseTypeName();
229
- const isDataObject = routingInfo.items[latestItem.context].resourceType === PCore.getConstants().RESOURCE_TYPES.DATA;
230
- const dataObjectAction = routingInfo.items[latestItem.context].resourceStatus;
231
- this.isMultiRecord = routingInfo.items[latestItem.context].isMultiRecordData;
232
- this.context$ = latestItem.context;
233
- this.title$ =
234
- isDataObject || this.isMultiRecord
235
- ? this.getModalHeading(dataObjectAction)
236
- : this.determineModalHeaderByAction(actionName, caseTypeName, ID, this.createdViewPConn$?.getCaseLocaleReference());
237
-
238
- const bIsRefComponent = this.checkIfRefComponent(newComp);
239
-
240
- if (bIsRefComponent) {
241
- const newPConn = ReferenceComponent.normalizePConn(newComp);
242
- this.arChildren$ = ReferenceComponent.normalizePConnArray(newPConn.getChildren());
243
- } else {
244
- // update children with new view's children
245
- this.arChildren$ = newComp.getChildren();
142
+ const { MULTIPLE } = PCore.getConstants().CONTAINER_TYPE;
143
+ const { key, latestItem } = this.getKeyAndLatestItem(routingInfo);
144
+
145
+ if (latestItem && type === MULTIPLE && (this.isOpenModalAction(accessedOrder) || this.isUpdateModalAction(accessedOrder))) {
146
+ const currentItem = routingInfo.items[key];
147
+ if (currentItem?.view && Object.keys(currentItem.view).length > 0) {
148
+ if (!this.bSubscribed) {
149
+ this.bSubscribed = true;
150
+ const { PUB_SUB_EVENTS } = PCore.getConstants();
151
+ PCore.getPubSubUtils().subscribe(
152
+ PUB_SUB_EVENTS.EVENT_SHOW_CANCEL_ALERT,
153
+ payload => {
154
+ this.showAlert(payload);
155
+ },
156
+ PUB_SUB_EVENTS.EVENT_SHOW_CANCEL_ALERT
157
+ );
246
158
  }
247
159
 
248
- this.bShowModal$ = true;
249
-
250
- // for when non modal
251
- this.modalVisibleChange.emit(this.bShowModal$);
252
-
253
- // save off itemKey to be used for finishAssignment, etc.
254
- this.itemKey$ = key;
255
-
256
- // cause a change for assignment
257
- this.updateToken$ = new Date().getTime();
258
- });
160
+ this.upsertModal(routingInfo, latestItem, key, accessedOrder);
161
+ }
162
+ } else if (this.isCloseModalAction(accessedOrder)) {
163
+ this.handleModalClose(accessedOrder);
259
164
  }
260
165
  }
261
166
 
262
- hideModal() {
263
- if (this.bShowModal$) {
264
- // other code in Nebula/Constellation not needed currently, but if so later,
265
- // should put here
167
+ // Builds/refreshes one modal-stack entry and pushes or updates it in-place
168
+ upsertModal(routingInfo, latestItem, key, accessedOrder) {
169
+ const entry = this.buildModalEntry(routingInfo, latestItem, key);
170
+
171
+ if (this.isUpdateModalAction(accessedOrder)) {
172
+ this.modalStack = this.modalStack.map(modal => (modal.key === key ? entry : modal));
173
+ } else if (this.isOpenModalAction(accessedOrder)) {
174
+ this.handleModalOpen(key);
175
+ this.modalStack = [...this.modalStack, entry];
266
176
  }
267
177
 
268
- this.ngZone.run(() => {
269
- this.bShowModal$ = false;
178
+ this.psService.sendMessage(false);
179
+ this.modalVisibleChange.emit(this.modalStack.length > 0);
180
+ this.cdRef.markForCheck();
181
+ }
270
182
 
271
- // for when non modal
272
- this.modalVisibleChange.emit(this.bShowModal$);
183
+ buildModalEntry(routingInfo, latestItem, key): ModalEntry {
184
+ const configObject = this.getConfigObject(latestItem, null, false);
185
+ // latestItem is only reached once its view metadata is populated (see updateSelf), so the
186
+ // created component is always present here — same assumption the old single-modal code made.
187
+ const newComp = configObject!.getPConnect();
188
+
189
+ const { actionName } = latestItem;
190
+ const theCaseInfo = newComp.getCaseInfo();
191
+ const ID = theCaseInfo.getBusinessID() || theCaseInfo.getID();
192
+ const caseTypeName = theCaseInfo.getCaseTypeName();
193
+
194
+ const isDataObject = routingInfo.items[latestItem.context].resourceType === PCore.getConstants().RESOURCE_TYPES.DATA;
195
+ const dataObjectAction = routingInfo.items[latestItem.context].resourceStatus;
196
+ const isMultiRecordData = routingInfo.items[latestItem.context].isMultiRecordData;
197
+
198
+ const title = this.getHeadingValue(
199
+ latestItem,
200
+ isMultiRecordData,
201
+ isDataObject,
202
+ actionName,
203
+ dataObjectAction,
204
+ caseTypeName,
205
+ ID,
206
+ newComp?.getCaseLocaleReference()
207
+ );
273
208
 
274
- this.oCaseInfo = {};
275
- });
209
+ const bIsRefComponent = this.checkIfRefComponent(newComp);
210
+ const arChildren$ = bIsRefComponent ? [newComp.getComponent()] : newComp.getChildren();
211
+
212
+ return {
213
+ key,
214
+ title,
215
+ createdViewPConn$: newComp,
216
+ arChildren$,
217
+ isMultiRecordData,
218
+ isDataObjectModal: isDataObject && !isMultiRecordData,
219
+ dataRecordKeys: latestItem.key || '',
220
+ dataObjectActionID: routingInfo.items[latestItem.context].actionID || '',
221
+ dataObjectAction: dataObjectAction || '',
222
+ dataObjectClassId: newComp.getValue('.classID') || '',
223
+ context: latestItem.context,
224
+ updateToken: new Date().getTime()
225
+ };
276
226
  }
277
227
 
278
228
  getConfigObject(item, pConnect, isReverseCoexistence = false) {
@@ -319,13 +269,17 @@ export class ModalViewContainerComponent implements OnInit, OnDestroy {
319
269
  this.bAlertState = bData;
320
270
  this.bShowCancelAlert$ = false;
321
271
  if (this.bAlertState) {
322
- this.hideModal();
272
+ // Discard confirmed — matches react-sdk: drop the whole stack rather than just the top entry
273
+ this.modalCollection = {};
274
+ this.modalStack = [];
275
+ this.modalVisibleChange.emit(false);
276
+ this.cdRef.markForCheck();
323
277
  }
324
278
  }
325
279
 
326
280
  showAlert(payload) {
327
281
  const { latestItem } = this.getKeyAndLatestItem(this.routingInfoRef.current);
328
- const { isModalAction } = payload;
282
+ const { isModalAction, hideDelete, isDataObject, skipReleaseLockRequest } = payload;
329
283
 
330
284
  /*
331
285
  If we are in create stage full page mode, created a new case and trying to click on cancel button
@@ -333,10 +287,12 @@ export class ModalViewContainerComponent implements OnInit, OnDestroy {
333
287
  */
334
288
  if (latestItem && isModalAction && !this.actionsDialog) {
335
289
  const configObject = this.getConfigObject(latestItem, this.pConn$);
336
- this.ngZone.run(() => {
337
- this.cancelPConn$ = configObject?.getPConnect();
338
- this.bShowCancelAlert$ = true;
339
- });
290
+ this.cancelPConn$ = configObject?.getPConnect();
291
+ this.cancelHideDelete$ = hideDelete;
292
+ this.cancelIsDataObject$ = isDataObject;
293
+ this.cancelSkipReleaseLockRequest$ = skipReleaseLockRequest;
294
+ this.bShowCancelAlert$ = true;
295
+ this.cdRef.markForCheck();
340
296
  }
341
297
  }
342
298
 
@@ -358,37 +314,62 @@ export class ModalViewContainerComponent implements OnInit, OnDestroy {
358
314
  return {};
359
315
  }
360
316
 
361
- compareCaseInfoIsDifferent(oCurrentCaseInfo: object): boolean {
362
- let bRet = false;
363
-
364
- // fast-deep-equal version
365
- if (isEqual !== undefined) {
366
- bRet = !isEqual(this.oCaseInfo, oCurrentCaseInfo);
367
- } else {
368
- const sCurrnentCaseInfo = JSON.stringify(oCurrentCaseInfo);
369
- const sOldCaseInfo = JSON.stringify(this.oCaseInfo);
370
- // stringify compare version
371
- if (sCurrnentCaseInfo != sOldCaseInfo) {
372
- bRet = true;
373
- }
374
- }
317
+ // Open/update/close are derived purely from how the count of known modals compares to
318
+ // routingInfo.accessedOrder — mirrors react-sdk's modal-stack fix so that closing one modal
319
+ // (removing one entry from accessedOrder) can never be mistaken for closing all of them.
320
+ isOpenModalAction(accessedOrder: string[]): boolean {
321
+ return Object.keys(this.modalCollection).length < accessedOrder.length;
322
+ }
375
323
 
376
- // if different, save off new case info
377
- if (bRet) {
378
- this.oCaseInfo = JSON.parse(JSON.stringify(oCurrentCaseInfo));
379
- }
324
+ isUpdateModalAction(accessedOrder: string[]): boolean {
325
+ return Object.keys(this.modalCollection).length === accessedOrder.length;
326
+ }
327
+
328
+ isCloseModalAction(accessedOrder: string[]): boolean {
329
+ return Object.keys(this.modalCollection).length > accessedOrder.length;
330
+ }
331
+
332
+ handleModalOpen(key: string) {
333
+ this.modalCollection = { ...this.modalCollection, [key]: {} };
334
+ }
380
335
 
381
- return bRet;
336
+ handleModalClose(accessedOrder: string[]) {
337
+ const closedModalKey = Object.keys(this.modalCollection).find(modalKey => !accessedOrder.includes(modalKey));
338
+
339
+ if (closedModalKey) {
340
+ const updatedModalCollection = { ...this.modalCollection };
341
+ delete updatedModalCollection[closedModalKey];
342
+ this.modalCollection = updatedModalCollection;
343
+
344
+ this.modalStack = this.modalStack.filter(modal => modal.key !== closedModalKey);
345
+ this.modalVisibleChange.emit(this.modalStack.length > 0);
346
+ this.bannerService.clearBanners(closedModalKey);
347
+ this.cdRef.markForCheck();
348
+ }
382
349
  }
383
350
 
384
- getBanners() {
385
- return getBanners({ target: this.itemKey$, ...this.stateProps$ });
351
+ getModalHeading(dataObjectAction, actionName) {
352
+ switch (dataObjectAction) {
353
+ case PCore.getConstants().RESOURCE_STATUS.CREATE:
354
+ return this.localizedVal('Add Record', this.localeCategory);
355
+ case PCore.getConstants().RESOURCE_STATUS.OPEN_FLOW_ACTION:
356
+ return this.localizedVal(actionName, this.localeCategory);
357
+ default:
358
+ return this.localizedVal('Edit Record', this.localeCategory);
359
+ }
386
360
  }
387
361
 
388
- getModalHeading(dataObjectAction) {
389
- return dataObjectAction === PCore.getConstants().RESOURCE_STATUS.CREATE
390
- ? this.localizedVal('Add Record', this.localeCategory)
391
- : this.localizedVal('Edit Record', this.localeCategory);
362
+ getHeadingValue(latestItem, isMultiRecordData, isDataObject, actionName, dataObjectAction, caseTypeName, ID, caseLocaleRef) {
363
+ if (isMultiRecordData) {
364
+ return latestItem.heading;
365
+ }
366
+ if (isDataObject) {
367
+ if (actionName) {
368
+ return this.localizedVal(actionName, this.localeCategory);
369
+ }
370
+ return this.getModalHeading(dataObjectAction, actionName);
371
+ }
372
+ return this.determineModalHeaderByAction(actionName, caseTypeName, ID, caseLocaleRef);
392
373
  }
393
374
 
394
375
  determineModalHeaderByAction(actionName, caseTypeName, ID, caseLocaleRef) {
@@ -398,15 +379,23 @@ export class ModalViewContainerComponent implements OnInit, OnDestroy {
398
379
  return `${this.localizedVal('Create', this.localeCategory)} ${this.localizedVal(caseTypeName, undefined, caseLocaleRef)} (${ID})`;
399
380
  }
400
381
 
401
- closeActionsDialog = () => {
382
+ // Closes one modal by key (bound per-instance in the template), or the topmost when omitted
383
+ closeActionsDialog = (modalKey?: string) => {
402
384
  this.actionsDialog = true;
403
- // this.ngZone.run(() => {
404
- this.bShowModal$ = false;
405
385
 
406
- // for when non modal
407
- this.modalVisibleChange.emit(this.bShowModal$);
386
+ this.modalStack = modalKey ? this.modalStack.filter(modal => modal.key !== modalKey) : this.modalStack.slice(0, -1);
408
387
 
409
- this.oCaseInfo = {};
410
- // });
388
+ this.modalVisibleChange.emit(this.modalStack.length > 0);
389
+ this.bannerService.clearBanners(modalKey ?? '');
390
+ this.cdRef.markForCheck();
411
391
  };
392
+
393
+ // Binds closeActionsDialog to a specific modal's key so closing one stacked modal never affects the others
394
+ closeModalFor(modalKey: string) {
395
+ return () => this.closeActionsDialog(modalKey);
396
+ }
397
+
398
+ trackByModalKey(index: number, modal: ModalEntry) {
399
+ return modal.key;
400
+ }
412
401
  }
@@ -26,6 +26,6 @@
26
26
  </ng-template>
27
27
  </div>
28
28
  <ng-template #isReference>
29
- <component-mapper name="View" [props]="{ pConn$: viewPConn$, displayOnlyFA$ }"></component-mapper>
29
+ <component-mapper name="reference" [props]="{ pConn$: viewPConn$, formGroup$, displayOnlyFA$ }"></component-mapper>
30
30
  </ng-template>
31
31
  </div>
@@ -1,9 +1,8 @@
1
- import { Component, OnInit, Input, NgZone, forwardRef, OnDestroy } from '@angular/core';
1
+ import { ChangeDetectorRef, Component, OnInit, Input, forwardRef, OnDestroy } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { FormGroup } from '@angular/forms';
4
4
  import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
5
5
  import { ProgressSpinnerService } from '@pega/angular-sdk-components';
6
- import { ReferenceComponent } from '@pega/angular-sdk-components';
7
6
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
8
7
  import { configureBrowserBookmark } from './helper';
9
8
 
@@ -57,7 +56,7 @@ export class ViewContainerComponent implements OnInit, OnDestroy {
57
56
  constructor(
58
57
  private angularPConnect: AngularPConnectService,
59
58
  private psService: ProgressSpinnerService,
60
- private ngZone: NgZone
59
+ private cdRef: ChangeDetectorRef
61
60
  ) {}
62
61
 
63
62
  ngOnInit() {
@@ -73,8 +72,7 @@ export class ViewContainerComponent implements OnInit, OnDestroy {
73
72
  // Then, continue on with other initialization
74
73
 
75
74
  // this.configProps$ = this.pConn$.getConfigProps();
76
- // children may have a 'reference' so normalize the children array
77
- this.arChildren$ = ReferenceComponent.normalizePConnArray(this.pConn$.getChildren());
75
+ this.arChildren$ = this.pConn$.getChildren();
78
76
 
79
77
  this.buildName$ = this.buildName();
80
78
  this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as ViewContainerProps;
@@ -146,8 +144,7 @@ export class ViewContainerComponent implements OnInit, OnDestroy {
146
144
  // *** DON'T call updateSelf in ngInit!! ***
147
145
 
148
146
  if (this.arChildren$ == null) {
149
- // children may have a 'reference' so normalize the children array
150
- this.arChildren$ = ReferenceComponent.normalizePConnArray(this.pConn$.getChildren());
147
+ this.arChildren$ = this.pConn$.getChildren();
151
148
  }
152
149
 
153
150
  // routingInfo was added as component prop in populateAdditionalProps
@@ -169,21 +166,19 @@ export class ViewContainerComponent implements OnInit, OnDestroy {
169
166
  const { accessedOrder, items } = routingInfo;
170
167
  if (accessedOrder && items) {
171
168
  const key = accessedOrder[accessedOrder.length - 1];
172
- let componentVisible = accessedOrder.length > 0;
173
- const { visible } = this.state;
174
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
175
- componentVisible = visible || componentVisible;
176
169
  if (items[key] && items[key].view && Object.keys(items[key].view).length > 0) {
177
170
  const latestItem = items[key];
178
171
  const rootView = latestItem.view;
179
172
  const { context, name: viewName } = rootView.config;
173
+ const target = key.substring(0, key.lastIndexOf('_'));
180
174
  const config: any = { meta: rootView };
181
175
  config.options = {
182
176
  context: latestItem.context,
183
177
  pageReference: context || this.pConn$.getPageReference(),
184
178
  containerName: this.pConn$.getContainerName(),
185
179
  containerItemName: key,
186
- hasForm: viewName === CREATE_DETAILS_VIEW_NAME
180
+ hasForm: viewName === CREATE_DETAILS_VIEW_NAME,
181
+ target
187
182
  };
188
183
  const configObject = PCore.createPConnect(config);
189
184
 
@@ -204,50 +199,48 @@ export class ViewContainerComponent implements OnInit, OnDestroy {
204
199
  // ViewContainer HTML template to guide what's rendered similar to what
205
200
  // the Nebula/Constellation return of React.Fragment does
206
201
 
207
- this.ngZone.run(() => {
208
- if (newComp.getComponentName() === 'reference') {
209
- // if a refernece, it will de reference to a "view"
210
- // so hand this off to the "View" component to do that
211
- this.isViewContainer$ = false;
212
- this.viewPConn$ = newComp;
202
+ if (newComp.getComponentName() === 'reference') {
203
+ // if a refernece, it will de reference to a "view"
204
+ // so hand this off to the "View" component to do that
205
+ this.isViewContainer$ = false;
206
+ this.viewPConn$ = newComp;
213
207
 
214
- /*
215
- *** this commmented out code should be removed, once we test out that
216
- *** handing off refernce to View component always works
217
- */
208
+ /*
209
+ *** this commmented out code should be removed, once we test out that
210
+ *** handing off refernce to View component always works
211
+ */
218
212
 
219
- // When newComp is a reference, we want to de-reference
220
- // it (to get the View) and then use that View to get the
221
- // template, title, children, etc.
213
+ // When newComp is a reference, we want to de-reference
214
+ // it (to get the View) and then use that View to get the
215
+ // template, title, children, etc.
222
216
 
223
- /*
217
+ /*
224
218
 
225
- const theDereferencedView = ReferenceComponent.normalizePConn(newComp);
219
+ const theDereferencedView = newComp;
226
220
  const newConfigProps = theDereferencedView.getConfigProps();
227
221
 
228
222
  // children may have a 'reference' so normalize the children arra
229
223
 
230
- const theDereferencedViewChildren = ReferenceComponent.normalizePConnArray(theDereferencedView.getChildren());
224
+ const theDereferencedViewChildren = theDereferencedView.getChildren();
231
225
  this.templateName$ = ('template' in newConfigProps) ? newConfigProps["template"] : "";
232
226
  this.title$ = ('title' in newConfigProps) ? newConfigProps["title"] : "";
233
227
  this.arChildren$ = theDereferencedViewChildren;
234
228
  this.createdViewPConn$ = theDereferencedView;
235
229
  */
236
- } else {
237
- // old style when newComp is NOT a 'reference'
238
- this.isViewContainer$ = true;
239
-
240
- console.error(`ViewContainer has a newComp that is NOT a reference!`);
241
-
242
- this.createdViewPConn$ = newComp;
243
- const newConfigProps = newComp.getConfigProps();
244
- this.templateName$ = newConfigProps.template || '';
245
- this.title$ = newConfigProps.title || '';
246
- // update children with new view's children
247
- // children may have a 'reference' so normalize the children array
248
- this.arChildren$ = ReferenceComponent.normalizePConnArray(newComp.getChildren());
249
- }
250
- });
230
+ } else {
231
+ // old style when newComp is NOT a 'reference'
232
+ this.isViewContainer$ = true;
233
+
234
+ console.error(`ViewContainer has a newComp that is NOT a reference!`);
235
+
236
+ this.createdViewPConn$ = newComp;
237
+ const newConfigProps = newComp.getConfigProps();
238
+ this.templateName$ = newConfigProps.template || '';
239
+ this.title$ = newConfigProps.title || '';
240
+ // update children with new view's children
241
+ this.arChildren$ = newComp.getChildren();
242
+ }
243
+ this.cdRef.markForCheck();
251
244
  }
252
245
  }
253
246
  }