@pega/angular-sdk-overrides 0.25.15 → 0.26.2

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 (86) 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/material-details-fields/material-details-fields.component.html +30 -21
  5. package/lib/designSystemExtension/operator/operator.component.ts +2 -1
  6. package/lib/designSystemExtension/rich-text-editor/rich-text-editor.component.html +104 -10
  7. package/lib/designSystemExtension/rich-text-editor/rich-text-editor.component.scss +141 -1
  8. package/lib/designSystemExtension/rich-text-editor/rich-text-editor.component.ts +224 -72
  9. package/lib/field/auto-complete/auto-complete.component.html +2 -1
  10. package/lib/field/auto-complete/auto-complete.component.ts +2 -0
  11. package/lib/field/check-box/check-box.component.html +4 -2
  12. package/lib/field/check-box/check-box.component.ts +10 -1
  13. package/lib/field/currency/currency.component.html +2 -1
  14. package/lib/field/currency/currency.component.ts +10 -1
  15. package/lib/field/date/date.component.html +2 -1
  16. package/lib/field/date/date.component.ts +2 -0
  17. package/lib/field/date-time/date-time.component.html +2 -1
  18. package/lib/field/date-time/date-time.component.scss +46 -40
  19. package/lib/field/date-time/date-time.component.ts +2 -0
  20. package/lib/field/decimal/decimal.component.html +2 -1
  21. package/lib/field/decimal/decimal.component.ts +2 -0
  22. package/lib/field/dropdown/dropdown.component.html +2 -1
  23. package/lib/field/dropdown/dropdown.component.ts +10 -1
  24. package/lib/field/email/email.component.html +2 -1
  25. package/lib/field/email/email.component.ts +2 -2
  26. package/lib/field/embedded-data-multi/embedded-data-multi.component.html +3 -0
  27. package/lib/field/embedded-data-multi/embedded-data-multi.component.scss +0 -0
  28. package/lib/field/embedded-data-multi/embedded-data-multi.component.ts +173 -0
  29. package/lib/field/field.base.ts +27 -1
  30. package/lib/field/integer/integer.component.html +2 -1
  31. package/lib/field/integer/integer.component.ts +4 -2
  32. package/lib/field/location/location.component.html +2 -1
  33. package/lib/field/location/location.component.ts +3 -1
  34. package/lib/field/multiselect/multiselect.component.html +1 -1
  35. package/lib/field/multiselect/multiselect.component.ts +22 -3
  36. package/lib/field/multiselect/utils.ts +5 -3
  37. package/lib/field/object-reference/object-reference.component.html +30 -15
  38. package/lib/field/object-reference/object-reference.component.ts +819 -94
  39. package/lib/field/percentage/percentage.component.html +2 -1
  40. package/lib/field/percentage/percentage.component.ts +10 -1
  41. package/lib/field/phone/phone.component.html +2 -1
  42. package/lib/field/phone/phone.component.ts +2 -1
  43. package/lib/field/radio-buttons/radio-buttons.component.html +2 -1
  44. package/lib/field/radio-buttons/radio-buttons.component.ts +10 -1
  45. package/lib/field/rich-text/rich-text.component.scss +1 -166
  46. package/lib/field/rich-text/rich-text.component.ts +1 -1
  47. package/lib/field/selectable-card/selectable-card.component.html +1 -0
  48. package/lib/field/selectable-card/selectable-card.component.ts +31 -16
  49. package/lib/field/semantic-link/semantic-link.component.ts +9 -5
  50. package/lib/field/text-area/text-area.component.html +2 -1
  51. package/lib/field/text-area/text-area.component.ts +2 -1
  52. package/lib/field/text-input/text-input.component.html +2 -1
  53. package/lib/field/text-input/text-input.component.ts +2 -1
  54. package/lib/field/time/time.component.html +2 -1
  55. package/lib/field/time/time.component.ts +2 -1
  56. package/lib/field/url/url.component.html +2 -1
  57. package/lib/field/url/url.component.ts +2 -1
  58. package/lib/field/user-reference/user-reference.component.html +4 -2
  59. package/lib/field/user-reference/user-reference.component.ts +10 -5
  60. package/lib/infra/Containers/flow-container/flow-container.component.ts +35 -46
  61. package/lib/infra/Containers/modal-view-container/modal-view-container.component.ts +46 -50
  62. package/lib/infra/Containers/view-container/view-container.component.ts +32 -31
  63. package/lib/infra/navbar/navbar.component.ts +33 -35
  64. package/lib/infra/root-container/root-container.component.ts +33 -38
  65. package/lib/template/app-shell/app-shell.component.ts +12 -11
  66. package/lib/template/base/details-template-base.ts +2 -1
  67. package/lib/template/data-reference/data-reference.component.ts +18 -27
  68. package/lib/template/data-reference/search-form/search-form.component.ts +7 -1
  69. package/lib/template/default-form/default-form.component.html +19 -3
  70. package/lib/template/default-form/default-form.component.ts +13 -3
  71. package/lib/template/simple-table/simple-table.component.ts +6 -0
  72. package/lib/template/simple-table-manual/helpers.ts +5 -5
  73. package/lib/template/simple-table-manual/simple-table-manual.component.html +29 -11
  74. package/lib/template/simple-table-manual/simple-table-manual.component.scss +4 -2
  75. package/lib/template/simple-table-manual/simple-table-manual.component.ts +82 -24
  76. package/lib/template/single-reference-readonly/single-reference-readonly.component.html +1 -1
  77. package/lib/template/single-reference-readonly/single-reference-readonly.component.scss +4 -0
  78. package/lib/template/single-reference-readonly/single-reference-readonly.component.ts +4 -4
  79. package/lib/template/wss-nav-bar/wss-nav-bar.component.ts +18 -20
  80. package/lib/widget/attachment/AttachmentUtils.ts +18 -10
  81. package/lib/widget/attachment/attachment.component.html +16 -6
  82. package/lib/widget/attachment/attachment.component.ts +12 -2
  83. package/lib/widget/case-history/case-history.component.ts +6 -2
  84. package/lib/widget/file-utility/file-utility.component.ts +25 -29
  85. package/lib/widget/todo/todo.component.ts +7 -2
  86. package/package.json +1 -1
@@ -75,7 +75,7 @@ export class DetailsTemplateBase implements OnInit, OnDestroy {
75
75
  fields?.forEach(field => {
76
76
  const thePConn = field.getPConnect();
77
77
  const theCompType = thePConn.getComponentName().toLowerCase();
78
- if (theCompType === 'reference' || theCompType === 'group') {
78
+ if (theCompType === 'reference' || theCompType === 'group' || theCompType === 'objectreference') {
79
79
  const configProps = thePConn.getConfigProps();
80
80
  configProps.readOnly = true;
81
81
  configProps.displayMode = 'DISPLAY_ONLY';
@@ -97,6 +97,7 @@ export class DetailsTemplateBase implements OnInit, OnDestroy {
97
97
  const theViewCont = PCore.createPConnect(viewContConfig);
98
98
  processedFields.push({
99
99
  type: theCompType,
100
+ config: thePConn.getConfigProps(),
100
101
  pConn: theViewCont?.getPConnect()
101
102
  });
102
103
  } else {
@@ -58,7 +58,6 @@ export class DataReferenceComponent implements OnInit, OnDestroy {
58
58
  dataRelationshipContext: any;
59
59
  imagePosition: any;
60
60
  showImageDescription: any;
61
- private isUpdatingFromDataCallback = false;
62
61
 
63
62
  constructor(
64
63
  private angularPConnect: AngularPConnectService,
@@ -70,30 +69,7 @@ export class DataReferenceComponent implements OnInit, OnDestroy {
70
69
  this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange);
71
70
  this.children = this.pConn$.getChildren();
72
71
  this.updateSelf();
73
- }
74
-
75
- ngOnDestroy(): void {
76
- if (this.angularPConnectData.unsubscribeFn) {
77
- this.angularPConnectData.unsubscribeFn();
78
- }
79
- }
80
-
81
- // Callback passed when subscribing to store change
82
- onStateChange() {
83
- // Should always check the bridge to see if the component should
84
- // update itself (re-render)
85
- const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this);
86
-
87
- // ONLY call updateSelf when the component should update
88
- if (bUpdateSelf) {
89
- this.updateSelf();
90
- }
91
- }
92
72
 
93
- getData() {
94
- if (this.isUpdatingFromDataCallback) {
95
- return;
96
- }
97
73
  if (
98
74
  this.rawViewMetadata.config?.parameters &&
99
75
  !this.isDDSourceDeferred &&
@@ -118,9 +94,7 @@ export class DataReferenceComponent implements OnInit, OnDestroy {
118
94
  }))
119
95
  .filter(item => item.key); // Filtering out undefined entries
120
96
  this.dropDownDataSource = ddDataSource;
121
- this.isUpdatingFromDataCallback = true;
122
97
  this.updateSelf();
123
- this.isUpdatingFromDataCallback = false;
124
98
  } else {
125
99
  const ddDataSource: any = [];
126
100
  this.dropDownDataSource = ddDataSource;
@@ -136,6 +110,24 @@ export class DataReferenceComponent implements OnInit, OnDestroy {
136
110
  }
137
111
  }
138
112
 
113
+ ngOnDestroy(): void {
114
+ if (this.angularPConnectData.unsubscribeFn) {
115
+ this.angularPConnectData.unsubscribeFn();
116
+ }
117
+ }
118
+
119
+ // Callback passed when subscribing to store change
120
+ onStateChange() {
121
+ // Should always check the bridge to see if the component should
122
+ // update itself (re-render)
123
+ const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this);
124
+
125
+ // ONLY call updateSelf when the component should update
126
+ if (bUpdateSelf) {
127
+ this.updateSelf();
128
+ }
129
+ }
130
+
139
131
  updateSelf() {
140
132
  // Update properties based on configProps
141
133
  const theConfigProps = this.pConn$.getConfigProps();
@@ -194,7 +186,6 @@ export class DataReferenceComponent implements OnInit, OnDestroy {
194
186
 
195
187
  this.generateChildrenToRender();
196
188
  this.displayChild = !(this.displaySingleRef || this.displayMultiRef);
197
- this.getData();
198
189
  }
199
190
 
200
191
  updatePropertiesFromProps(theConfigProps) {
@@ -37,6 +37,7 @@ export class SearchFormComponent implements OnInit, OnChanges {
37
37
  @Input() pConn$: typeof PConnect;
38
38
  @Input() formGroup$: FormGroup;
39
39
  @Input() searchSelectCacheKey;
40
+ @Input() type: string;
40
41
 
41
42
  configProps$: any;
42
43
  isInitialized = false;
@@ -58,7 +59,12 @@ export class SearchFormComponent implements OnInit, OnChanges {
58
59
  this.isInitialized = true;
59
60
  this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps());
60
61
  this.propsToUse = { ...this.pConn$.getInheritedProps() };
61
- this.deferLoadedTabs = this.pConn$.getChildren()[2];
62
+ // When called from ObjectReference, pConn$ itself acts as deferLoadedTabs (no children[2])
63
+ if (this.type === 'ObjectReference') {
64
+ this.deferLoadedTabs = { getPConnect: () => this.pConn$ };
65
+ } else {
66
+ this.deferLoadedTabs = this.pConn$.getChildren()[2];
67
+ }
62
68
  const cache: any = PCore.getNavigationUtils().getComponentCache(this.searchSelectCacheKey) ?? {};
63
69
  const { selectedCategory } = cache;
64
70
  const firstTabId = getFirstVisibleTabId(this.deferLoadedTabs, selectedCategory);
@@ -1,6 +1,22 @@
1
- <div *ngIf="instructions" class="psdk-default-form-instruction-text">
2
- <div key="instructions" id="instruction-text" [innerHTML]="instructions"></div>
3
- </div>
1
+ <ng-container *ngIf="instructions && bShowInstructions$">
2
+ <component-mapper
3
+ *ngIf="instructionBannerVariant$; else instructionText"
4
+ name="Alert"
5
+ [props]="{
6
+ message: instructions,
7
+ messageIsHtml: true,
8
+ severity: instructionBannerVariant$,
9
+ hideClose: !bDismissInstructions$
10
+ }"
11
+ [parent]="this"
12
+ [outputEvents]="{ onClose: dismissInstructions }"
13
+ ></component-mapper>
14
+ <ng-template #instructionText>
15
+ <div class="psdk-default-form-instruction-text">
16
+ <div key="instructions" id="instruction-text" [innerHTML]="instructions"></div>
17
+ </div>
18
+ </ng-template>
19
+ </ng-container>
4
20
  <div [className]="divClass$">
5
21
  <div *ngFor="let kid of arChildren$" [ngClass]="{ 'grid-column': kid.getPConnect().getComponentName() === 'reference' }">
6
22
  <component-mapper
@@ -3,7 +3,7 @@ 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 { ComponentMapperComponent } from '@pega/angular-sdk-components';
6
- import { TemplateUtils } from '@pega/angular-sdk-components';
6
+ import { InstructionObject, TemplateUtils } from '@pega/angular-sdk-components';
7
7
  import { FormTemplateBase } from '@pega/angular-sdk-components';
8
8
 
9
9
  function areViewsChanged(oldViews: any[], newViews: any[]): boolean {
@@ -20,7 +20,7 @@ function areViewsChanged(oldViews: any[], newViews: any[]): boolean {
20
20
  interface DefaultFormProps {
21
21
  // If any, enter additional props that only exist on this component
22
22
  NumCols: string;
23
- instructions: string;
23
+ instructions?: string | InstructionObject;
24
24
  }
25
25
 
26
26
  @Component({
@@ -38,7 +38,10 @@ export class DefaultFormComponent extends FormTemplateBase implements OnInit, On
38
38
 
39
39
  arChildren$: any[];
40
40
  divClass$: string;
41
- instructions: string;
41
+ instructions: string | undefined;
42
+ instructionBannerVariant$: 'warning' | 'info' | 'success' | undefined;
43
+ bDismissInstructions$ = false;
44
+ bShowInstructions$ = true;
42
45
 
43
46
  constructor(
44
47
  private angularPConnect: AngularPConnectService,
@@ -70,6 +73,9 @@ export class DefaultFormComponent extends FormTemplateBase implements OnInit, On
70
73
  const configProps = this.pConn$.getConfigProps() as DefaultFormProps;
71
74
  const kids = this.pConn$.getChildren();
72
75
  this.instructions = this.templateUtils.getInstructions(this.pConn$, configProps?.instructions);
76
+ const instructionsType = this.templateUtils.getInstructionsType(configProps?.instructions);
77
+ this.instructionBannerVariant$ = instructionsType ? this.templateUtils.mapInstructionsTypeToBannerVariant(instructionsType) : undefined;
78
+ this.bDismissInstructions$ = this.templateUtils.getDismissBanner(configProps?.instructions);
73
79
 
74
80
  const numCols = configProps.NumCols ? configProps.NumCols : '1';
75
81
  switch (numCols) {
@@ -96,4 +102,8 @@ export class DefaultFormComponent extends FormTemplateBase implements OnInit, On
96
102
  this.arChildren$ = children;
97
103
  }
98
104
  }
105
+
106
+ dismissInstructions() {
107
+ this.bShowInstructions$ = false;
108
+ }
99
109
  }
@@ -82,6 +82,11 @@ export class SimpleTableComponent implements OnInit, OnDestroy {
82
82
  // moved this from ngOnInit() and call this from there instead...
83
83
  this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as SimpleTableProps;
84
84
 
85
+ // Reset rendering state on every update
86
+ this.fieldGroupProps = null;
87
+ this.listViewProps = null;
88
+ this.refToPConnect = null;
89
+
85
90
  if (this.configProps$.visibility != null) {
86
91
  this.bVisible$ = this.bVisible$ = this.utils.getBooleanValue(this.configProps$.visibility);
87
92
  }
@@ -95,6 +100,7 @@ export class SimpleTableComponent implements OnInit, OnDestroy {
95
100
  }
96
101
  if (multiRecordDisplayAs === 'fieldGroup') {
97
102
  this.fieldGroupProps = { ...this.configProps$, contextClass };
103
+ return;
98
104
  }
99
105
 
100
106
  const {
@@ -233,7 +233,7 @@ export const updateFieldLabels = (fields, configFields, primaryFieldsViewIndex,
233
233
  return labelsOfFields;
234
234
  };
235
235
 
236
- export const buildFieldsForTable = (configFields, pConnect, showDeleteButton, options) => {
236
+ export const buildFieldsForTable = (configFields, pConnect, showActionColumn, options) => {
237
237
  const { primaryFieldsViewIndex, fields } = options;
238
238
 
239
239
  // get resolved field labels for primary fields raw config included in configFields
@@ -260,8 +260,8 @@ export const buildFieldsForTable = (configFields, pConnect, showDeleteButton, op
260
260
  };
261
261
  });
262
262
 
263
- // ONLY add DELETE_ICON to fields when the table is requested as EDITABLE
264
- if (showDeleteButton) {
263
+ // Add the action column when either edit or delete is available.
264
+ if (showActionColumn) {
265
265
  fieldDefs.push({
266
266
  type: 'text',
267
267
  label: '',
@@ -354,8 +354,8 @@ export const filterDataByDate = (item, filterObj) => {
354
354
 
355
355
  export const filterDataByCommonFields = (item, filterObj) => {
356
356
  let bKeep = true;
357
- const value = item[filterObj.ref].toLowerCase();
358
- const filterValue = filterObj.containsFilterValue.toLowerCase();
357
+ const value = String(item?.[filterObj.ref] ?? '').toLowerCase();
358
+ const filterValue = String(filterObj.containsFilterValue ?? '').toLowerCase();
359
359
 
360
360
  switch (filterObj.containsFilter) {
361
361
  case 'contains':
@@ -3,7 +3,14 @@
3
3
  <h3 *ngIf="label" className="label" style="font-weight: bold">
4
4
  {{ label }} <span class="results-count">{{ getResultsText() }}</span>
5
5
  </h3>
6
- <table *ngIf="readOnlyMode || allowEditingInModal" mat-table [dataSource]="elementsData" class="mat-elevation-z8" id="readonly-table" matSort>
6
+ <table
7
+ *ngIf="readOnlyMode || allowEditingInModal || hideEditRow"
8
+ mat-table
9
+ [dataSource]="elementsData"
10
+ class="mat-elevation-z8"
11
+ id="readonly-table"
12
+ matSort
13
+ >
7
14
  <ng-container *ngFor="let dCol of processedFields; let i = index" [matColumnDef]="dCol.config.name">
8
15
  <th mat-header-cell *matHeaderCellDef mat-sort-header (click)="_headerSortClick($event, dCol)" arrowPosition="before">
9
16
  <div>{{ dCol.config.label }}</div>
@@ -39,20 +46,25 @@
39
46
  </td>
40
47
  </ng-container>
41
48
  <ng-container matColumnDef="DeleteIcon">
42
- <div *ngIf="allowEditingInModal">
43
- <th mat-header-cell *matHeaderCellDef></th>
44
- <td mat-cell *matCellDef="let element; index as j">
45
- <div class="header-icon">
49
+ <th mat-header-cell *matHeaderCellDef></th>
50
+ <td mat-cell *matCellDef="let element; index as j">
51
+ <ng-container *ngIf="allowEditingInModal; else deleteOnly">
52
+ <div *ngIf="rowActions[j]?.hasAnyAction" class="header-icon">
46
53
  <button mat-icon-button [matMenuTriggerFor]="utilityMenu">
47
54
  <mat-icon>more_vert</mat-icon>
48
55
  </button>
49
56
  <mat-menu #utilityMenu="matMenu" overlapTrigger="false">
50
- <button mat-menu-item (click)="editRecord(element, j)">Edit</button>
51
- <button mat-menu-item (click)="deleteRecord(j)">Delete</button>
57
+ <button *ngIf="rowActions[j]?.canEdit" mat-menu-item (click)="editRecord(element, element.__originalIndex)">Edit</button>
58
+ <button *ngIf="rowActions[j]?.canDelete" mat-menu-item (click)="deleteRecord(element.__originalIndex)">Delete</button>
52
59
  </mat-menu>
53
60
  </div>
54
- </td>
55
- </div>
61
+ </ng-container>
62
+ <ng-template #deleteOnly>
63
+ <button *ngIf="rowActions[j]?.canDelete" id="delete-button" mat-icon-button (click)="deleteRecord(j)">
64
+ <mat-icon>delete</mat-icon>
65
+ </button>
66
+ </ng-template>
67
+ </td>
56
68
  </ng-container>
57
69
  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
58
70
  <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
@@ -62,7 +74,13 @@
62
74
  </td>
63
75
  </tr>
64
76
  </table>
65
- <table *ngIf="editableMode && !allowEditingInModal" mat-table [dataSource]="elementsData" class="mat-elevation-z8" id="editable-table">
77
+ <table
78
+ *ngIf="editableMode && !allowEditingInModal && !hideEditRow"
79
+ mat-table
80
+ [dataSource]="elementsData"
81
+ class="mat-elevation-z8"
82
+ id="editable-table"
83
+ >
66
84
  <ng-container *ngFor="let dCol of fieldDefs; let i = index">
67
85
  <ng-container *ngIf="dCol.name != 'DeleteIcon'" [matColumnDef]="dCol.name">
68
86
  <th mat-header-cell *matHeaderCellDef class="psdk-mat-header">{{ dCol.label }}</th>
@@ -81,7 +99,7 @@
81
99
  <ng-container matColumnDef="DeleteIcon">
82
100
  <th mat-header-cell *matHeaderCellDef></th>
83
101
  <td mat-cell *matCellDef="let element; index as j">
84
- <button id="delete-button" mat-icon-button (click)="deleteRecord(j)">
102
+ <button *ngIf="rowActions[j]?.canDelete" id="delete-button" mat-icon-button (click)="deleteRecord(j)">
85
103
  <mat-icon>delete</mat-icon>
86
104
  </button>
87
105
  </td>
@@ -130,6 +130,7 @@ td.mat-mdc-cell:last-child {
130
130
  align-items: center;
131
131
  height: 100%;
132
132
  width: 100%;
133
+ background-color: var(--app-dialog-background-color);
133
134
  position: fixed;
134
135
  z-index: 999;
135
136
  top: 0px;
@@ -140,10 +141,11 @@ td.mat-mdc-cell:last-child {
140
141
  display: table;
141
142
  margin: auto;
142
143
  min-width: 150px;
143
- border: 1px solid var(--app-inverse-form-color);
144
+ background-color: var(--mat-sys-surface-container);
145
+ border: 1px solid var(--mat-sys-outline-variant);
144
146
  border-radius: 10px;
145
147
  padding: 20px;
146
- box-shadow: 0 0 10px 3px var(--app-box-shadow-color);
148
+ box-shadow: 0 0 10px 3px var(--mat-sys-level3);
147
149
  }
148
150
 
149
151
  tr.mat-mdc-row {
@@ -39,6 +39,7 @@ interface SimpleTableManualProps {
39
39
  allowActions?: any;
40
40
  allowTableEdit?: boolean;
41
41
  allowRowDelete?: any;
42
+ allowRowEdit?: any;
42
43
  editMode?: string;
43
44
  addAndEditRowsWithin?: any;
44
45
  viewForAddAndEditModal?: any;
@@ -59,6 +60,12 @@ class Group {
59
60
  }
60
61
  }
61
62
 
63
+ interface RowActions {
64
+ canEdit: boolean;
65
+ canDelete: boolean;
66
+ hasAnyAction: boolean;
67
+ }
68
+
62
69
  @Component({
63
70
  selector: 'app-simple-table-manual',
64
71
  templateUrl: './simple-table-manual.component.html',
@@ -92,7 +99,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
92
99
 
93
100
  bVisible$ = true;
94
101
  displayedColumns: string[] = [];
95
- rowData: MatTableDataSource<any>;
102
+ rowData = new MatTableDataSource<any>([]);
96
103
  originalData: any[] = [];
97
104
  processedFields: any[] = [];
98
105
  fieldDefs: any[] = [];
@@ -159,6 +166,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
159
166
  referenceListStr: any;
160
167
  bUseSeparateViewForEdit: any;
161
168
  editView: any;
169
+ editType: any;
162
170
  defaultActionId: any;
163
171
  editActionId: any;
164
172
  settingsSvgIcon$: string;
@@ -167,7 +175,12 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
167
175
  targetClassLabel: string;
168
176
  localizedVal = PCore.getLocaleUtils().getLocaleValue;
169
177
  localeCategory = 'SimpleTable';
170
- editType: any;
178
+ hideEditRow: any;
179
+ hideDeleteRow: boolean;
180
+ showEditButton: boolean;
181
+ showDeleteButton: boolean;
182
+ showActionColumn: boolean;
183
+ rowActions: RowActions[] = [];
171
184
  constructor(
172
185
  private angularPConnect: AngularPConnectService,
173
186
  public utils: Utils,
@@ -238,7 +251,6 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
238
251
  presets,
239
252
  allowActions,
240
253
  allowTableEdit,
241
- allowRowDelete,
242
254
  label: labelProp,
243
255
  propertyLabel,
244
256
  fieldMetadata,
@@ -305,9 +317,15 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
305
317
  this.editableMode = renderMode === 'Editable';
306
318
  const isDisplayModeEnabled = displayMode === 'DISPLAY_ONLY';
307
319
  this.showAddRowButton = !this.readOnlyMode && !simpleTableManualProps.hideAddRow;
320
+ this.hideEditRow = simpleTableManualProps.hideEditRow;
321
+ this.hideDeleteRow = simpleTableManualProps.hideDeleteRow;
308
322
  this.allowEditingInModal =
309
323
  (editMode ? editMode === 'modal' : addAndEditRowsWithin === 'modal') && !(renderMode === 'ReadOnly' || isDisplayModeEnabled);
310
- const showDeleteButton = this.editableMode && !simpleTableManualProps.hideDeleteRow && evaluateAllowRowAction(allowRowDelete, this.rowData);
324
+ this.showEditButton = this.allowEditingInModal && !this.hideEditRow;
325
+ this.showDeleteButton = this.editableMode && !this.hideDeleteRow;
326
+ this.showActionColumn = this.showEditButton || this.showDeleteButton;
327
+ const { allowRowEdit, allowRowDelete } = this.pConn$.getComponentConfig?.() ?? {};
328
+ this.rowActions = this.referenceList.map(row => this.getRowActions(row, allowRowEdit, allowRowDelete));
311
329
  this.defaultView = editModeConfig ? editModeConfig.defaultView : viewForAddAndEditModal;
312
330
  this.bUseSeparateViewForEdit = editModeConfig ? editModeConfig.useSeparateViewForEdit : useSeparateViewForEdit;
313
331
  this.editView = editModeConfig ? editModeConfig.editView : viewForEditModal;
@@ -326,7 +344,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
326
344
  // Nebula does). It will also have the "label", and "meta" contains the original,
327
345
  // unchanged config info. For now, much of the info here is carried over from
328
346
  // Nebula and we may not end up using it all.
329
- this.fieldDefs = buildFieldsForTable(rawFields, this.pConn$, showDeleteButton, {
347
+ this.fieldDefs = buildFieldsForTable(rawFields, this.pConn$, this.showActionColumn, {
330
348
  primaryFieldsViewIndex,
331
349
  fields: resolvedFields
332
350
  });
@@ -364,7 +382,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
364
382
  }
365
383
 
366
384
  // for edit and adding rows in modal view and to generate readonly list
367
- if (!isEqual(this.prevReferenceList, this.referenceList) && (this.readOnlyMode || this.allowEditingInModal)) {
385
+ if (!isEqual(this.prevReferenceList, this.referenceList) && (this.readOnlyMode || this.allowEditingInModal || this.hideEditRow)) {
368
386
  this.generateRowsData();
369
387
  }
370
388
 
@@ -391,17 +409,21 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
391
409
  }
392
410
 
393
411
  initializeDefaultPageInstructions() {
394
- if (this.isInitialized) {
395
- this.isInitialized = false;
396
- if (this.allowEditingInModal) {
397
- this.pConn$.getListActions().initDefaultPageInstructions(
398
- this.pConn$.getReferenceList(),
399
- this.fieldDefs.filter(item => item.name).map(item => item.name)
400
- );
401
- } else {
402
- // @ts-ignore - An argument for 'propertyNames' was not provided.
403
- this.pConn$.getListActions().initDefaultPageInstructions(this.pConn$.getReferenceList());
404
- }
412
+ if (!this.isInitialized) {
413
+ return;
414
+ }
415
+
416
+ this.isInitialized = false;
417
+
418
+ if (this.allowEditingInModal) {
419
+ this.pConn$.getListActions().initDefaultPageInstructions(
420
+ this.pConn$.getReferenceList(),
421
+ // Temporary filter for attachments to align with constellation payload behavior.
422
+ this.fieldDefs.filter(item => item.name && item.meta?.type !== 'Attachment').map(item => item.name)
423
+ );
424
+ } else {
425
+ // @ts-ignore - An argument for 'propertyNames' was not provided.
426
+ this.pConn$.getListActions().initDefaultPageInstructions(this.pConn$.getReferenceList());
405
427
  }
406
428
  }
407
429
 
@@ -410,6 +432,31 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
410
432
  return `${recordsCount || 0} result${recordsCount > 1 ? 's' : ''}`;
411
433
  }
412
434
 
435
+ private getRowActions(row: any, allowRowEdit: any, allowRowDelete: any): RowActions {
436
+ const canEdit = this.showEditButton && evaluateAllowRowAction(allowRowEdit, row);
437
+ const canDelete = this.showDeleteButton && this.isDeleteAllowedForRow(row, allowRowDelete);
438
+
439
+ return {
440
+ canEdit,
441
+ canDelete,
442
+ hasAnyAction: canEdit || canDelete
443
+ };
444
+ }
445
+
446
+ private isDeleteAllowedForRow(row: any, allowRowDelete: any): boolean {
447
+ if (allowRowDelete === undefined || allowRowDelete === true) return true;
448
+ if (typeof allowRowDelete === 'string' && allowRowDelete.startsWith('@E ')) {
449
+ try {
450
+ const expression = allowRowDelete.replace('@E ', '');
451
+ // @ts-expect-error - options param is optional per corejs docs
452
+ return PCore.getExpressionEngine().evaluate(expression, row);
453
+ } catch {
454
+ return true;
455
+ }
456
+ }
457
+ return false;
458
+ }
459
+
413
460
  sortCompare(a, b): number {
414
461
  let aValue = a[0][this.compareRef];
415
462
  let bValue = b[0][this.compareRef];
@@ -929,9 +976,13 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
929
976
  // See what data (if any) we have to display
930
977
  const refKeys: string[] = inColKey.split('.');
931
978
  let valBuilder = inRowData;
979
+ let index = 0;
980
+
932
981
  for (const key of refKeys) {
933
- valBuilder = valBuilder[key] ? valBuilder[key] : valBuilder;
982
+ index += 1;
983
+ valBuilder = valBuilder[key] !== undefined || index === refKeys.length ? valBuilder[key] : valBuilder;
934
984
  }
985
+
935
986
  return valBuilder;
936
987
  }
937
988
 
@@ -988,30 +1039,37 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
988
1039
  }
989
1040
 
990
1041
  editRecord(data, index) {
991
- if (data) {
1042
+ if (data && Number.isInteger(index) && index >= 0 && index < this.referenceList.length) {
1043
+ const viewForEdit = this.bUseSeparateViewForEdit ? this.editView : this.defaultView;
992
1044
  this.pConn$
993
1045
  .getActionsApi()
994
- // @ts-expect-error
995
1046
  .openEmbeddedDataModal(
996
- this.bUseSeparateViewForEdit ? this.editView : this.defaultView,
1047
+ viewForEdit,
997
1048
  this.pConn$ as any,
998
1049
  this.referenceListStr,
999
1050
  index,
1000
1051
  PCore.getConstants().RESOURCE_STATUS.UPDATE,
1001
- this.targetClassLabel
1052
+ this.targetClassLabel,
1053
+ this.editType,
1054
+ this.editActionId
1002
1055
  );
1003
1056
  }
1004
1057
  }
1005
1058
 
1006
1059
  deleteRecord(index) {
1007
- this.pConn$.getListActions().deleteEntry(index);
1060
+ if (Number.isInteger(index) && index >= 0 && index < this.referenceList.length) {
1061
+ this.pConn$.getListActions().deleteEntry(index);
1062
+ }
1008
1063
  }
1009
1064
 
1010
1065
  buildElementsForTable() {
1011
1066
  const context = this.pConn$.getContextName();
1067
+ const { allowRowEdit } = this.pConn$.getComponentConfig?.() ?? {};
1012
1068
  const eleData: any = [];
1013
1069
  this.referenceList.forEach((element, index) => {
1070
+ const isRowEditable = evaluateAllowRowAction(allowRowEdit, element);
1014
1071
  const data: any = [];
1072
+ data.__originalIndex = index;
1015
1073
  this.rawFields?.forEach(item => {
1016
1074
  if (!item?.config?.hide) {
1017
1075
  item = {
@@ -1019,7 +1077,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
1019
1077
  config: {
1020
1078
  ...item.config,
1021
1079
  label: '',
1022
- displayMode: this.readOnlyMode || this.allowEditingInModal ? 'DISPLAY_ONLY' : undefined
1080
+ displayMode: this.readOnlyMode || this.allowEditingInModal || this.hideEditRow || !isRowEditable ? 'DISPLAY_ONLY' : undefined
1023
1081
  }
1024
1082
  };
1025
1083
  const referenceListData = getReferenceList(this.pConn$);
@@ -1,4 +1,4 @@
1
- <div [ngClass]="displayMode ? 'psdk-grid-display' : 'psdk-grid-nondisplay'">
1
+ <div [ngClass]="displayMode ? 'psdk-grid-display' : 'psdk-grid-nondisplay'" [class.psdk-details-reference-value]="isDetails$">
2
2
  <div *ngIf="label" class="psdk-grid-label">{{ label }}</div>
3
3
  <component-mapper name="SemanticLink" [props]="{ pConn$: newPconn, formGroup$ }"></component-mapper>
4
4
  </div>
@@ -11,6 +11,10 @@
11
11
  margin-top: 1rem;
12
12
  }
13
13
 
14
+ .psdk-details-reference-value {
15
+ margin-top: 0;
16
+ }
17
+
14
18
  .psdk-label {
15
19
  color: var(--app-label-color);
16
20
  margin: 8px 0px;
@@ -14,7 +14,8 @@ import { getDataRelationshipContextFromKey } from '@pega/angular-sdk-components'
14
14
  export class SingleReferenceReadonlyComponent implements OnInit, OnDestroy {
15
15
  @Input() pConn$: typeof PConnect;
16
16
  @Input() formGroup$: FormGroup;
17
- @Input() dataRelationshipContext?: any;
17
+ @Input() dataRelationshipContext: any = null;
18
+ @Input() isDetails$ = false;
18
19
 
19
20
  angularPConnectData: AngularPConnectData = {};
20
21
  configProps: any;
@@ -66,9 +67,8 @@ export class SingleReferenceReadonlyComponent implements OnInit, OnDestroy {
66
67
  const hideLabel = this.configProps.hideLabel;
67
68
  // const additionalFields = this.configProps.additionalFields;
68
69
  const displayAs = this.configProps.displayAs ?? 'readonly';
69
- const dataRelationshipContext = (rawViewMetadata?.config as any)?.displayField
70
- ? getDataRelationshipContextFromKey((rawViewMetadata?.config as any)?.displayField)
71
- : this.dataRelationshipContext;
70
+ const dataRelationshipContext =
71
+ this.dataRelationshipContext ?? getDataRelationshipContextFromKey((rawViewMetadata?.config as any)?.displayField ?? '');
72
72
  if (propsToUse.showLabel === false) {
73
73
  propsToUse.label = '';
74
74
  }