@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,4 +1,5 @@
1
1
  import { Component, forwardRef } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
2
3
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
3
4
  import { DetailsTemplateBase } from '@pega/angular-sdk-components';
4
5
 
@@ -6,47 +7,6 @@ import { DetailsTemplateBase } from '@pega/angular-sdk-components';
6
7
  selector: 'app-details-wide-narrow',
7
8
  templateUrl: './details-wide-narrow.component.html',
8
9
  styleUrls: ['./details-wide-narrow.component.scss'],
9
- imports: [forwardRef(() => ComponentMapperComponent)]
10
+ imports: [CommonModule, forwardRef(() => ComponentMapperComponent)]
10
11
  })
11
- export class DetailsWideNarrowComponent extends DetailsTemplateBase {
12
- override pConn$: typeof PConnect;
13
-
14
- highlightedDataArr: any[] = [];
15
- showHighlightedData: boolean;
16
- arFields$: any[] = [];
17
- arFields2$: any[] = [];
18
- propsToUse: any = {};
19
-
20
- override updateSelf() {
21
- const rawMetaData: any = this.pConn$.resolveConfigProps(this.pConn$.getRawMetadata()?.config);
22
- this.showHighlightedData = rawMetaData?.showHighlightedData;
23
-
24
- if (this.showHighlightedData) {
25
- const highlightedData = rawMetaData?.highlightedData;
26
- this.highlightedDataArr = highlightedData.map(field => {
27
- field.config.displayMode = 'STACKED_LARGE_VAL';
28
-
29
- if (field.config.value === '@P .pyStatusWork') {
30
- field.type = 'TextInput';
31
- field.config.displayAsStatus = true;
32
- }
33
-
34
- return field;
35
- });
36
- }
37
-
38
- this.pConn$.setInheritedProp('displayMode', 'DISPLAY_ONLY');
39
- this.pConn$.setInheritedProp('readOnly', true);
40
-
41
- const kids = this.pConn$.getChildren() as any[];
42
- for (const kid of kids) {
43
- const pKid = kid.getPConnect();
44
- const pKidData = pKid.resolveConfigProps(pKid.getRawMetadata());
45
- if (kids.indexOf(kid) == 0) {
46
- this.arFields$ = pKidData.children;
47
- } else {
48
- this.arFields2$ = pKidData.children;
49
- }
50
- }
51
- }
52
- }
12
+ export class DetailsWideNarrowComponent extends DetailsTemplateBase {}
@@ -4,5 +4,6 @@
4
4
  <mat-tab-group id="dynamic-tabs" mat-stretch-tabs="false" animationDuration="0">
5
5
  <mat-tab *ngFor="let tab of tabsItems" [label]="tab.name">
6
6
  <component-mapper name="View" [props]="{ pConn$: tab.content.getPConnect() }"></component-mapper>
7
+ <component-mapper name="reference" [props]="{ pConn$: tab.content.getPConnect() }"></component-mapper>
7
8
  </mat-tab>
8
9
  </mat-tab-group>
@@ -43,6 +43,7 @@ export class FieldGroupTemplateComponent implements OnInit, OnDestroy, OnChanges
43
43
  readonlyMode: boolean;
44
44
  contextClass: any;
45
45
  heading: any;
46
+ headingPath: string[] = [];
46
47
  children: any;
47
48
  menuIconOverride$: any;
48
49
  referenceListLength = signal<number | null>(null);
@@ -131,8 +132,7 @@ export class FieldGroupTemplateComponent implements OnInit, OnDestroy, OnChanges
131
132
  }
132
133
 
133
134
  if (this.referenceListLength() != referenceList?.length) {
134
- // @ts-ignore - Expected 3 arguments, but got 1
135
- this.pConn$.getListActions().initDefaultPageInstructions(resolvedList);
135
+ this.pConn$.getListActions().initDefaultPageInstructions(resolvedList, []);
136
136
 
137
137
  this.children = referenceList?.map((item, index) => {
138
138
  return {
@@ -150,11 +150,24 @@ export class FieldGroupTemplateComponent implements OnInit, OnDestroy, OnChanges
150
150
  return `${heading} ${index + 1}`;
151
151
  };
152
152
 
153
- getDynamicHeader = (item, index) => {
154
- if (this.heading && item[this.heading.substring(1)]) {
155
- return item[this.heading.substring(1)];
153
+ getDynamicHeader = (item: Record<string, unknown>, index: number): string => {
154
+ if (this.heading) {
155
+ let value: any = item;
156
+ this.headingPath = this.heading.substring(1).split('.');
157
+
158
+ for (const key of this.headingPath) {
159
+ if (value === null || typeof value !== 'object' || !(key in value)) {
160
+ value = undefined;
161
+ break;
162
+ }
163
+ value = Reflect.get(value, key);
164
+ }
165
+
166
+ if (value !== undefined && value !== null && value !== '') {
167
+ return value.toString();
168
+ }
156
169
  }
157
- return `Row ${index + 1}`;
170
+ return `${PCore.getLocaleUtils().getLocaleValue('Row', 'SimpleTable')} ${index + 1}`;
158
171
  };
159
172
 
160
173
  addFieldGroupItem() {
@@ -21,3 +21,20 @@
21
21
  .psdk-val-labels-left {
22
22
  white-space: break-spaces;
23
23
  }
24
+
25
+ .psdk-container-stacked-large-val {
26
+ margin: 8px 0;
27
+ }
28
+
29
+ .psdk-container-stacked-large-val .psdk-grid-label {
30
+ color: rgba(0, 0, 0, 0.6);
31
+ font-size: 0.875rem;
32
+ font-weight: 400;
33
+ line-height: 1.5;
34
+ }
35
+
36
+ .psdk-val-stacked {
37
+ color: rgba(0, 0, 0, 0.87);
38
+ font-size: 1.25rem;
39
+ line-height: 1.5;
40
+ }
@@ -1,4 +1,4 @@
1
- import { Component, OnInit, Input, forwardRef, SimpleChanges, OnChanges } from '@angular/core';
1
+ import { Component, OnInit, Input, forwardRef } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { FormGroup, FormBuilder } from '@angular/forms';
4
4
  import { buildFilterComponents } from '@pega/angular-sdk-components';
@@ -17,7 +17,7 @@ interface InlineDashboardPageProps {
17
17
  styleUrls: ['./inline-dashboard-page.component.scss'],
18
18
  imports: [CommonModule, forwardRef(() => ComponentMapperComponent)]
19
19
  })
20
- export class InlineDashboardPageComponent implements OnInit, OnChanges {
20
+ export class InlineDashboardPageComponent implements OnInit {
21
21
  @Input() pConn$: typeof PConnect;
22
22
 
23
23
  configProps$: InlineDashboardPageProps;
@@ -34,14 +34,6 @@ export class InlineDashboardPageComponent implements OnInit, OnChanges {
34
34
  this.updateSelf();
35
35
  }
36
36
 
37
- ngOnChanges(changes: SimpleChanges): void {
38
- const { pConn$ } = changes;
39
-
40
- if (pConn$.previousValue && pConn$.previousValue !== pConn$.currentValue) {
41
- this.updateSelf();
42
- }
43
- }
44
-
45
37
  updateSelf() {
46
38
  this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as InlineDashboardPageProps;
47
39
  const arChildren$ = this.pConn$.getChildren();
@@ -18,6 +18,7 @@ import { DragDropModule, CdkDragDrop, moveItemInArray, CdkDropList, CdkDrag } fr
18
18
  import { ProgressSpinnerService } from '@pega/angular-sdk-components';
19
19
  import { Utils } from '@pega/angular-sdk-components';
20
20
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
21
+ import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
21
22
  import { getCurrencyOptions } from '@pega/angular-sdk-components';
22
23
  import { getLocale, getSeconds } from '@pega/angular-sdk-components';
23
24
  import { formatters } from '@pega/angular-sdk-components';
@@ -162,18 +163,28 @@ export class ListViewComponent implements OnInit, OnDestroy {
162
163
  paging: any;
163
164
  fieldDefs: any;
164
165
  checkBoxValue: string;
166
+ // Last value seen on the bound property, used to detect external changes.
167
+ lastSelectedPropValue: any;
165
168
  label?: string = '';
166
169
  uniqueId = crypto.randomUUID();
167
170
  displayAs: any;
168
171
  showRecords: any;
169
172
  identifier: string;
170
173
  promotedFiltersId: string;
174
+
175
+ // Used with AngularPConnect
176
+ angularPConnectData: AngularPConnectData = {};
177
+
171
178
  constructor(
179
+ private angularPConnect: AngularPConnectService,
172
180
  private psService: ProgressSpinnerService,
173
181
  public utils: Utils
174
182
  ) {}
175
183
 
176
184
  ngOnInit(): void {
185
+ // First thing in initialization is registering and subscribing to the AngularPConnect service
186
+ this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange);
187
+
177
188
  this.configProps$ = this.pConn$.getConfigProps() as ListViewProps;
178
189
  /** By default, pyGUID is used for Data classes and pyID is for Work classes as row-id/key */
179
190
  const defRowID = this.configProps$?.referenceType === 'Case' ? 'pyID' : 'pyGUID';
@@ -197,6 +208,7 @@ export class ListViewComponent implements OnInit, OnDestroy {
197
208
  this.selectionMode = this.configProps$.selectionMode;
198
209
 
199
210
  this.checkBoxValue = this.configProps$.value;
211
+ this.lastSelectedPropValue = this.configProps$.value;
200
212
 
201
213
  this.arFilterMainButtons$.push({ actionID: 'submit', jsAction: 'submit', name: 'Submit' });
202
214
  this.arFilterSecondaryButtons$.push({ actionID: 'cancel', jsAction: 'cancel', name: 'Cancel' });
@@ -266,6 +278,29 @@ export class ListViewComponent implements OnInit, OnDestroy {
266
278
  this.clearSelectionsAndUpdateTable(this.pConn$, this.uniqueId, this.configProps$?.viewName);
267
279
  }
268
280
 
281
+ onStateChange() {
282
+ // Should always check the bridge to see if the component should
283
+ // update itself (re-render)
284
+ const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this);
285
+
286
+ // ONLY call updateSelf when the component should update
287
+ if (bUpdateSelf) {
288
+ this.updateSelf();
289
+ }
290
+ }
291
+
292
+ updateSelf(): void {
293
+ // The selected row is driven by the bound property, which another field on the screen may change.
294
+ const latestConfigProps = this.pConn$.getConfigProps() as ListViewProps;
295
+ const latestValue = latestConfigProps?.value;
296
+
297
+ // Only re-sync on an actual property change, so a row the user just picked is not reverted.
298
+ if (this.selectionMode === SELECTION_MODE.SINGLE && latestValue !== this.lastSelectedPropValue) {
299
+ this.lastSelectedPropValue = latestValue;
300
+ this.checkBoxValue = latestValue;
301
+ }
302
+ }
303
+
269
304
  clearSelectionsAndUpdateTable(getPConnect: any, uniqueId: string, viewName): void {
270
305
  const clearSelectionsAndRefreshList = ({ viewName: name, clearSelections }: any) => {
271
306
  if (name === viewName) {
@@ -351,7 +386,7 @@ export class ListViewComponent implements OnInit, OnDestroy {
351
386
  }
352
387
 
353
388
  getValue(col) {
354
- return this.fieldDefs.find(f => f.name === col)?.label;
389
+ return this.fields$.find(f => f.config.name === col)?.config.label || this.fieldDefs.find(f => f.name === col)?.label;
355
390
  }
356
391
 
357
392
  getListData() {
@@ -487,6 +522,10 @@ export class ListViewComponent implements OnInit, OnDestroy {
487
522
  // }
488
523
 
489
524
  ngOnDestroy() {
525
+ if (this.angularPConnectData.unsubscribeFn) {
526
+ this.angularPConnectData.unsubscribeFn();
527
+ }
528
+
490
529
  PCore.getPubSubUtils().unsubscribe(
491
530
  PCore.getConstants().PUB_SUB_EVENTS.EVENT_DASHBOARD_FILTER_CHANGE,
492
531
  `dashboard-component-${'id'}`,
@@ -586,11 +625,10 @@ export class ListViewComponent implements OnInit, OnDestroy {
586
625
  }
587
626
 
588
627
  _getIconStyle(level): string {
589
- let sReturn = '';
590
628
  let nLevel = parseInt(level, 10);
591
629
  nLevel--;
592
630
  nLevel *= 15;
593
- sReturn = `padding-left: ${nLevel}px; vertical-align: middle`;
631
+ const sReturn = `padding-left: ${nLevel}px; vertical-align: middle`;
594
632
 
595
633
  return sReturn;
596
634
  }
@@ -963,16 +1001,14 @@ export class ListViewComponent implements OnInit, OnDestroy {
963
1001
  let bKeep = true;
964
1002
  for (const filterObj of this.filterByColumns) {
965
1003
  if (filterObj.containsFilterValue != '' || filterObj.containsFilter == 'null' || filterObj.containsFilter == 'notnull') {
966
- let filterValue: any;
967
-
968
1004
  switch (filterObj.type) {
969
1005
  case 'Date':
970
1006
  case 'DateTime':
971
1007
  case 'Time':
972
- bKeep = this.filterDataWithDate(item, filterObj, filterValue);
1008
+ bKeep = this.filterDataWithDate(item, filterObj);
973
1009
  break;
974
1010
  default:
975
- bKeep = this.filterDataWithCommonTypes(item, filterObj, filterValue);
1011
+ bKeep = this.filterDataWithCommonTypes(item, filterObj);
976
1012
  break;
977
1013
  }
978
1014
  }
@@ -986,10 +1022,10 @@ export class ListViewComponent implements OnInit, OnDestroy {
986
1022
  return bKeep;
987
1023
  }
988
1024
 
989
- filterDataWithDate(item, filterObj, filterValue) {
1025
+ filterDataWithDate(item, filterObj) {
990
1026
  let bKeep;
991
1027
  let value = item[filterObj.ref] != null || item[filterObj.ref] != '' ? getSeconds(item[filterObj.ref]) : null;
992
- filterValue = filterObj.containsFilterValue != null && filterObj.containsFilterValue != '' ? getSeconds(filterObj.containsFilterValue) : null;
1028
+ let filterValue = filterObj.containsFilterValue != null && filterObj.containsFilterValue != '' ? getSeconds(filterObj.containsFilterValue) : null;
993
1029
 
994
1030
  switch (filterObj.containsFilter) {
995
1031
  case 'notequal':
@@ -1032,10 +1068,10 @@ export class ListViewComponent implements OnInit, OnDestroy {
1032
1068
  return bKeep;
1033
1069
  }
1034
1070
 
1035
- filterDataWithCommonTypes(item, filterObj, filterValue) {
1071
+ filterDataWithCommonTypes(item, filterObj) {
1036
1072
  let bKeep;
1037
1073
  const value = item[filterObj.ref].toLowerCase();
1038
- filterValue = filterObj.containsFilterValue.toLowerCase();
1074
+ const filterValue = filterObj.containsFilterValue.toLowerCase();
1039
1075
 
1040
1076
  switch (filterObj.containsFilter) {
1041
1077
  case 'contains':
@@ -5,6 +5,9 @@
5
5
  <div *ngIf="kid.getPConnect().getRawMetadata()['type'] === 'View'">
6
6
  <component-mapper name="View" [props]="{ pConn$: kid.getPConnect(), formGroup$ }"></component-mapper>
7
7
  </div>
8
+ <div *ngIf="kid.getPConnect().getRawMetadata()['type'] === 'reference'">
9
+ <component-mapper name="reference" [props]="{ pConn$: kid.getPConnect(), formGroup$ }"></component-mapper>
10
+ </div>
8
11
  <div *ngIf="kid.getPConnect().getRawMetadata()['type'] === 'CaseCreateStage'">
9
12
  <component-mapper name="CaseCreateStage" [props]="{ pConn$: kid.getPConnect(), formGroup$ }"></component-mapper>
10
13
  </div>
@@ -2,6 +2,7 @@
2
2
  <div *ngFor="let kid of arChildren$">
3
3
  <div [ngSwitch]="kid.getPConnect().getComponentName()">
4
4
  <component-mapper *ngSwitchCase="'View'" name="View" [props]="{ pConn$: kid.getPConnect() }"></component-mapper>
5
+ <component-mapper *ngSwitchCase="'reference'" name="reference" [props]="{ pConn$: kid.getPConnect() }"></component-mapper>
5
6
  <component-mapper *ngSwitchCase="'Region'" name="Region" [props]="{ pConn$: kid.getPConnect() }"></component-mapper>
6
7
  <div *ngSwitchDefault>Page Missing: {{ kid.getPConnect().getComponentName() }}</div>
7
8
  </div>
@@ -5,6 +5,7 @@
5
5
  <div *ngFor="let kid of arChildren$">
6
6
  <div [ngSwitch]="kid.getPConnect().getComponentName()">
7
7
  <component-mapper *ngSwitchCase="'View'" name="View" [props]="{ pConn$: kid.getPConnect() }"></component-mapper>
8
+ <component-mapper *ngSwitchCase="'reference'" name="reference" [props]="{ pConn$: kid.getPConnect() }"></component-mapper>
8
9
  <component-mapper *ngSwitchCase="'Region'" name="Region" [props]="{ pConn$: kid.getPConnect() }"></component-mapper>
9
10
  <div *ngSwitchDefault>Page Missing: {{ kid.getPConnect().getComponentName() }}</div>
10
11
  </div>
@@ -2,7 +2,9 @@
2
2
  <div class="psdk-self-service-case-view-header">
3
3
  <div class="heading">{{ this.heading$ }}</div>
4
4
  <div *ngIf="showCaseActions" class="psdk-case-view-buttons">
5
- <button mat-raised-button color="secondary" [matMenuTriggerFor]="actionMenu">{{ localizedVal('Actions...', localeCategory) }}</button>
5
+ <button mat-raised-button color="secondary" [matMenuTriggerFor]="actionMenu" [disabled]="bActionsMenuDisabled$">
6
+ {{ localizedVal('Actions...', localeCategory) }}
7
+ </button>
6
8
  <mat-menu #actionMenu="matMenu" overlapTrigger="false">
7
9
  <ng-container *ngFor="let action of arAvailableActions$">
8
10
  <button mat-menu-item (click)="_menuActionClick(action)">
@@ -14,6 +16,16 @@
14
16
  {{ process.name }}
15
17
  </button>
16
18
  </ng-container>
19
+ <ng-container *ngFor="let action of arDataObjectActions$">
20
+ <button mat-menu-item (click)="_menuDataObjectActionClick(action)">
21
+ {{ localizedVal(action.name, '', localeKey) }}
22
+ </button>
23
+ </ng-container>
24
+ <ng-container *ngFor="let action of arCreateCaseActions$">
25
+ <button mat-menu-item (click)="_menuCreateCaseActionClick(action)">
26
+ {{ localizedVal(action.name, '', localeKey) }}
27
+ </button>
28
+ </ng-container>
17
29
  </mat-menu>
18
30
  </div>
19
31
  </div>
@@ -1,24 +1,109 @@
1
- import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2
-
3
1
  import { SelfServiceCaseViewComponent } from './self-service-case-view.component';
4
2
 
5
3
  describe('SelfServiceCaseViewComponent', () => {
6
4
  let component: SelfServiceCaseViewComponent;
7
- let fixture: ComponentFixture<SelfServiceCaseViewComponent>;
5
+ let actionsApi: { openDataObjectAction: jasmine.Spy; createWork: jasmine.Spy };
6
+ let dataInfoActions: any;
7
+ let configProps: any;
8
+ let dataRecord: any;
8
9
 
9
- beforeEach(waitForAsync(() => {
10
- TestBed.configureTestingModule({
11
- declarations: [SelfServiceCaseViewComponent]
12
- }).compileComponents();
13
- }));
10
+ const utilityChild = {
11
+ getPConnect: () => ({ getRawMetadata: () => ({ type: 'region', name: 'Utilities', children: [] }) })
12
+ };
14
13
 
15
14
  beforeEach(() => {
16
- fixture = TestBed.createComponent(SelfServiceCaseViewComponent);
17
- component = fixture.componentInstance;
18
- fixture.detectChanges();
15
+ (globalThis as any).PCore = {
16
+ getLocaleUtils: () => ({ getLocaleValue: (value: string) => value }),
17
+ getCaseUtils: () => ({ isObjectCaseType: () => false })
18
+ };
19
+
20
+ actionsApi = {
21
+ openDataObjectAction: jasmine.createSpy('openDataObjectAction'),
22
+ createWork: jasmine.createSpy('createWork')
23
+ };
24
+ dataInfoActions = undefined;
25
+ dataRecord = { PlanID: 'P-1' };
26
+ // Summary region is switched off so the test does not depend on case summary metadata.
27
+ configProps = { icon: 'case', header: 'Header', subheader: 'ID-1', showSummaryRegion: false, showCaseActions: true };
28
+
29
+ const utils = {
30
+ getImageSrc: () => '',
31
+ getSDKStaticContentUrl: () => '',
32
+ getBooleanValue: (value: any) => value === true || value === 'true'
33
+ } as any;
34
+
35
+ component = new SelfServiceCaseViewComponent({} as any, utils);
36
+ component.pConn$ = {
37
+ resolveConfigProps: () => configProps,
38
+ getConfigProps: () => configProps,
39
+ getCaseLocaleReference: () => 'MY-CLASS!CASE!MY-CASE',
40
+ getChildren: () => [utilityChild, utilityChild, utilityChild, utilityChild, utilityChild],
41
+ getLocalizationService: () => ({ getLocalizedText: (value: string) => value }),
42
+ getDataObject: () => ({ caseInfo: { ID: 'C-1', availableActions: [], availableProcesses: [] } }),
43
+ getValue: (prop: string, context?: string) => {
44
+ if (prop === '.actions' && context === 'dataInfo') return dataInfoActions;
45
+ if (prop === '.content' && context === 'dataInfo') return dataRecord;
46
+ if (prop === '.classID' && context === 'dataInfo.content') return 'My-Data-Class';
47
+ if (context === '') return dataRecord[prop.slice(1)];
48
+ return undefined;
49
+ },
50
+ getActionsApi: () => actionsApi
51
+ } as any;
52
+ component.localizedVal = (value: string) => value;
19
53
  });
20
54
 
21
55
  it('should create', () => {
22
56
  expect(component).toBeTruthy();
23
57
  });
58
+
59
+ it('lists data object actions published under dataInfo', () => {
60
+ dataInfoActions = {
61
+ availableActions: [{ ID: 'Edit', name: 'Edit' }],
62
+ availableCreateCaseActions: [{ ID: 'My-Work-Class', name: 'Request Plan Change' }]
63
+ };
64
+
65
+ component.fullUpdate();
66
+
67
+ expect(component.arDataObjectActions$.length).toBe(1);
68
+ expect(component.arCreateCaseActions$.length).toBe(1);
69
+ expect(component.bActionsMenuDisabled$).toBeFalse();
70
+ });
71
+
72
+ it('falls back to empty arrays and disables the menu when nothing is available', () => {
73
+ component.fullUpdate();
74
+
75
+ expect(component.arDataObjectActions$).toEqual([]);
76
+ expect(component.arCreateCaseActions$).toEqual([]);
77
+ expect(component.bActionsMenuDisabled$).toBeTrue();
78
+ });
79
+
80
+ it('keeps honouring the showCaseActions configuration flag', () => {
81
+ configProps = { ...configProps, showCaseActions: false };
82
+
83
+ component.fullUpdate();
84
+
85
+ expect(component.showCaseActions).toBeFalse();
86
+ });
87
+
88
+ it('preserves the case locale reference used for action labels', () => {
89
+ component.fullUpdate();
90
+
91
+ expect(component.localeKey).toBe('MY-CLASS!CASE!MY-CASE');
92
+ });
93
+
94
+ it('opens a data object action with the record class and content', () => {
95
+ component._menuDataObjectActionClick({ ID: 'updateCVV', name: 'Update CVV' });
96
+
97
+ expect(actionsApi.openDataObjectAction).toHaveBeenCalledWith('My-Data-Class', dataRecord, 'updateCVV', 'Update CVV');
98
+ });
99
+
100
+ it('starts a new case with starting fields nested under the target reference field', () => {
101
+ component._menuCreateCaseActionClick({
102
+ ID: 'My-Work-Class',
103
+ name: 'Request Plan Change',
104
+ targetDataReferenceField: { field: 'PlanRef', inputs: [{ linkedField: 'PlanID' }] }
105
+ });
106
+
107
+ expect(actionsApi.createWork).toHaveBeenCalledWith('My-Work-Class', { startingFields: { PlanRef: { PlanID: 'P-1' } } });
108
+ });
24
109
  });
@@ -9,6 +9,7 @@ import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-c
9
9
  import { Utils } from '@pega/angular-sdk-components';
10
10
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
11
11
  import { prepareCaseSummaryData } from '@pega/angular-sdk-components';
12
+ import { CreateCaseAction, DataObjectAction, DataObjectActions } from '@pega/angular-sdk-components';
12
13
 
13
14
  interface SelfServiceCaseViewProps {
14
15
  // If any, enter additional props that only exist on this component
@@ -45,6 +46,9 @@ export class SelfServiceCaseViewComponent implements OnInit, OnDestroy {
45
46
 
46
47
  arAvailableActions$: any[] = [];
47
48
  arAvailabeProcesses$: any[] = [];
49
+ arDataObjectActions$: DataObjectAction[] = [];
50
+ arCreateCaseActions$: CreateCaseAction[] = [];
51
+ bActionsMenuDisabled$ = true;
48
52
 
49
53
  caseSummaryPConn$: any;
50
54
  currentCaseID = '';
@@ -102,10 +106,31 @@ export class SelfServiceCaseViewComponent implements OnInit, OnDestroy {
102
106
  sessionStorage.setItem('okToInitFlowContainer', 'true');
103
107
  } else {
104
108
  this.updateHeaderAndSummary();
109
+ this.updateCaseActions();
105
110
  }
106
111
  }
107
112
  }
108
113
 
114
+ // React re-reads every action source on each render. Here fullUpdate is gated on a case ID
115
+ // change and so runs once, while actions (and a data object's `dataInfo.actions`) arrive
116
+ // later, so they are all refreshed on every store update instead.
117
+ updateCaseActions() {
118
+ const caseInfo = this.pConn$.getDataObject()?.caseInfo ?? {};
119
+ this.arAvailableActions$ = caseInfo.availableActions ?? [];
120
+ this.arAvailabeProcesses$ = caseInfo.availableProcesses ?? [];
121
+ this.editAction = this.arAvailableActions$.find(action => action.ID === 'pyUpdateCaseDetails');
122
+
123
+ const dataInfoActions: DataObjectActions = this.pConn$.getValue('.actions', 'dataInfo') ?? {};
124
+ this.arDataObjectActions$ = dataInfoActions.availableActions ?? [];
125
+ this.arCreateCaseActions$ = dataInfoActions.availableCreateCaseActions ?? [];
126
+
127
+ this.bActionsMenuDisabled$ =
128
+ this.arAvailableActions$.length === 0 &&
129
+ this.arAvailabeProcesses$.length === 0 &&
130
+ this.arDataObjectActions$.length === 0 &&
131
+ this.arCreateCaseActions$.length === 0;
132
+ }
133
+
109
134
  hasCaseIDChanged(): boolean {
110
135
  if (this.currentCaseID !== this.pConn$.getDataObject().caseInfo.ID) {
111
136
  this.currentCaseID = this.pConn$.getDataObject().caseInfo.ID;
@@ -144,9 +169,8 @@ export class SelfServiceCaseViewComponent implements OnInit, OnDestroy {
144
169
 
145
170
  const caseInfo = this.pConn$.getDataObject().caseInfo;
146
171
  this.currentCaseID = caseInfo.ID;
147
- this.arAvailableActions$ = caseInfo?.availableActions ? caseInfo.availableActions : [];
148
- this.editAction = this.arAvailableActions$.find(action => action.ID === 'pyUpdateCaseDetails');
149
- this.arAvailabeProcesses$ = caseInfo?.availableProcesses ? caseInfo.availableProcesses : [];
172
+
173
+ this.updateCaseActions();
150
174
 
151
175
  const { showCaseLifecycle = true, showSummaryRegion = true, showUtilitiesRegion = true, showCaseActions = true, caseClass } = this.configProps$;
152
176
  this.showCaseLifecycle = this.utils.getBooleanValue(showCaseLifecycle);
@@ -204,4 +228,29 @@ export class SelfServiceCaseViewComponent implements OnInit, OnDestroy {
204
228
 
205
229
  openProcessAction(data.ID, { ...data });
206
230
  }
231
+
232
+ _menuDataObjectActionClick(action: DataObjectAction) {
233
+ const actionsAPI = this.pConn$.getActionsApi();
234
+ const openDataObjectAction = actionsAPI.openDataObjectAction.bind(actionsAPI);
235
+ const classID = this.pConn$.getValue('.classID', 'dataInfo.content');
236
+ const dataRecord = this.pConn$.getValue('.content', 'dataInfo');
237
+
238
+ openDataObjectAction(classID, dataRecord, action.ID, this.localizedVal(action.name, '', this.localeKey));
239
+ }
240
+
241
+ _menuCreateCaseActionClick(action: CreateCaseAction) {
242
+ const actionsAPI = this.pConn$.getActionsApi();
243
+ const createWork = actionsAPI.createWork.bind(actionsAPI);
244
+ const { field, inputs } = action.targetDataReferenceField ?? {};
245
+ const startingFields: Record<string, any> = {};
246
+
247
+ // The engine expects the linked values nested under the target reference field.
248
+ if (field) {
249
+ inputs?.forEach(input => {
250
+ startingFields[field] = { ...startingFields[field], [input.linkedField]: this.pConn$.getValue(`.${input.linkedField}`, '') };
251
+ });
252
+ }
253
+
254
+ createWork(action.ID, { startingFields });
255
+ }
207
256
  }
@@ -5,6 +5,7 @@ import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-c
5
5
  import { Utils } from '@pega/angular-sdk-components';
6
6
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
7
7
  import { buildMetaForListView, getContext } from '@pega/angular-sdk-components';
8
+ import { getReferenceList } from '@pega/angular-sdk-components';
8
9
 
9
10
  interface SimpleTableProps {
10
11
  // If any, enter additional props that only exist on this component
@@ -66,9 +67,12 @@ export class SimpleTableComponent implements OnInit, OnDestroy {
66
67
  // Should always check the bridge to see if the component should
67
68
  // update itself (re-render)
68
69
  const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this);
69
-
70
+ const resolvedList = getReferenceList(this.pConn$);
71
+ this.pConn$.setReferenceList(resolvedList);
70
72
  // ONLY call updateSelf when the component should update
71
73
  if (bUpdateSelf) {
74
+ const resolvedList = getReferenceList(this.pConn$);
75
+ this.pConn$.setReferenceList(resolvedList);
72
76
  this.updateSelf();
73
77
  }
74
78
  }
@@ -78,6 +82,11 @@ export class SimpleTableComponent implements OnInit, OnDestroy {
78
82
  // moved this from ngOnInit() and call this from there instead...
79
83
  this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as SimpleTableProps;
80
84
 
85
+ // Reset rendering state on every update
86
+ this.fieldGroupProps = null;
87
+ this.listViewProps = null;
88
+ this.refToPConnect = null;
89
+
81
90
  if (this.configProps$.visibility != null) {
82
91
  this.bVisible$ = this.bVisible$ = this.utils.getBooleanValue(this.configProps$.visibility);
83
92
  }
@@ -91,6 +100,7 @@ export class SimpleTableComponent implements OnInit, OnDestroy {
91
100
  }
92
101
  if (multiRecordDisplayAs === 'fieldGroup') {
93
102
  this.fieldGroupProps = { ...this.configProps$, contextClass };
103
+ return;
94
104
  }
95
105
 
96
106
  const {