@pega/angular-sdk-overrides 25.1.13 → 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 (153) 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 +15 -5
  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 +1 -1
  74. package/lib/infra/Containers/flow-container/flow-container.component.ts +35 -46
  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 -194
  80. package/lib/infra/Containers/view-container/view-container.component.ts +32 -35
  81. package/lib/infra/assignment/assignment.component.html +2 -1
  82. package/lib/infra/assignment/assignment.component.ts +42 -15
  83. package/lib/infra/defer-load/defer-load.component.ts +6 -3
  84. package/lib/infra/multi-step/multi-step.component.html +25 -33
  85. package/lib/infra/multi-step/multi-step.component.scss +67 -125
  86. package/lib/infra/multi-step/multi-step.component.ts +11 -0
  87. package/lib/infra/navbar/navbar.component.ts +33 -36
  88. package/lib/infra/reference/reference.component.ts +1 -2
  89. package/lib/infra/root-container/root-container.component.ts +33 -38
  90. package/lib/infra/view/view.component.ts +21 -40
  91. package/lib/template/advanced-search/advanced-search.component.ts +0 -1
  92. package/lib/template/advanced-search/search-groups/search-groups.component.ts +2 -3
  93. package/lib/template/app-shell/app-shell.component.ts +13 -13
  94. package/lib/template/base/details-template-base.ts +41 -14
  95. package/lib/template/case-summary/case-summary.component.ts +15 -1
  96. package/lib/template/case-view/case-view.component.html +13 -1
  97. package/lib/template/case-view/case-view.component.spec.ts +119 -10
  98. package/lib/template/case-view/case-view.component.ts +52 -3
  99. package/lib/template/data-reference/data-reference.component.ts +2 -4
  100. package/lib/template/data-reference/search-form/search-form.component.html +1 -1
  101. package/lib/template/data-reference/search-form/search-form.component.ts +9 -1
  102. package/lib/template/data-reference/search-form/tabsData.ts +0 -1
  103. package/lib/template/default-form/default-form.component.html +19 -3
  104. package/lib/template/default-form/default-form.component.ts +13 -3
  105. package/lib/template/details/details.component.html +23 -3
  106. package/lib/template/details/details.component.scss +9 -2
  107. package/lib/template/details/details.component.ts +3 -70
  108. package/lib/template/details-narrow-wide/details-narrow-wide.component.html +21 -2
  109. package/lib/template/details-narrow-wide/details-narrow-wide.component.scss +8 -1
  110. package/lib/template/details-narrow-wide/details-narrow-wide.component.ts +3 -39
  111. package/lib/template/details-one-column/details-one-column.component.html +23 -1
  112. package/lib/template/details-one-column/details-one-column.component.scss +14 -0
  113. package/lib/template/details-one-column/details-one-column.component.ts +3 -40
  114. package/lib/template/details-three-column/details-three-column.component.html +21 -2
  115. package/lib/template/details-three-column/details-three-column.component.scss +8 -1
  116. package/lib/template/details-three-column/details-three-column.component.ts +3 -48
  117. package/lib/template/details-two-column/details-two-column.component.html +21 -2
  118. package/lib/template/details-two-column/details-two-column.component.scss +8 -1
  119. package/lib/template/details-two-column/details-two-column.component.ts +3 -46
  120. package/lib/template/details-wide-narrow/details-wide-narrow.component.html +21 -2
  121. package/lib/template/details-wide-narrow/details-wide-narrow.component.scss +8 -1
  122. package/lib/template/details-wide-narrow/details-wide-narrow.component.ts +3 -43
  123. package/lib/template/field-group-template/field-group-template.component.ts +19 -6
  124. package/lib/template/field-value-list/field-value-list.component.scss +17 -0
  125. package/lib/template/list-view/list-view.component.ts +47 -11
  126. package/lib/template/self-service-case-view/self-service-case-view.component.html +13 -1
  127. package/lib/template/self-service-case-view/self-service-case-view.component.spec.ts +96 -11
  128. package/lib/template/self-service-case-view/self-service-case-view.component.ts +52 -3
  129. package/lib/template/simple-table/simple-table.component.ts +6 -0
  130. package/lib/template/simple-table-manual/helpers.ts +84 -16
  131. package/lib/template/simple-table-manual/simple-table-manual.component.html +30 -14
  132. package/lib/template/simple-table-manual/simple-table-manual.component.scss +8 -2
  133. package/lib/template/simple-table-manual/simple-table-manual.component.ts +131 -43
  134. package/lib/template/single-reference-readonly/single-reference-readonly.component.html +0 -0
  135. package/lib/template/single-reference-readonly/single-reference-readonly.component.scss +2 -3
  136. package/lib/template/single-reference-readonly/single-reference-readonly.component.ts +7 -8
  137. package/lib/template/wss-nav-bar/wss-nav-bar.component.ts +19 -21
  138. package/lib/widget/attachment/AttachmentUtils.ts +19 -11
  139. package/lib/widget/attachment/attachment.component.html +16 -6
  140. package/lib/widget/attachment/attachment.component.ts +14 -4
  141. package/lib/widget/case-history/case-history.component.ts +6 -2
  142. package/lib/widget/feed-container/feed-container.component.ts +1 -199
  143. package/lib/widget/file-utility/file-utility.component.ts +26 -30
  144. package/lib/widget/todo/todo.component.ts +7 -2
  145. package/package.json +2 -2
  146. package/lib/designSystemExtension/material-details/material-details.component.html +0 -40
  147. package/lib/designSystemExtension/material-details/material-details.component.scss +0 -116
  148. package/lib/designSystemExtension/material-details/material-details.component.spec.ts +0 -24
  149. package/lib/designSystemExtension/material-details/material-details.component.ts +0 -31
  150. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.html +0 -29
  151. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.scss +0 -34
  152. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.spec.ts +0 -22
  153. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.ts +0 -37
@@ -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 {
@@ -148,12 +148,33 @@ const SUPPORTED_FIELD_TYPES = [
148
148
  'RichText'
149
149
  ];
150
150
 
151
+ // PCore.getNameSpaceUtils() exists at runtime but is missing from the pcore typedefs.
152
+ export const getQualifiedPrimaryFieldsName = (): string =>
153
+ (PCore as any).getNameSpaceUtils?.()?.getDefaultQualifiedName(PRIMARY_FIELDS) ?? PRIMARY_FIELDS;
154
+
155
+ export const isPrimaryFieldsValue = (value): boolean => value === PRIMARY_FIELDS || value === getQualifiedPrimaryFieldsName();
156
+
157
+ /**
158
+ * Strips annotation prefixes (ex: "@P .FirstName") and the leading dot from a raw config value.
159
+ */
160
+ export const getPropertyNameFromConfigValue = (configValue): string => {
161
+ let name = configValue ?? '';
162
+ if (name.startsWith('@')) {
163
+ name = name.substring(name.indexOf(' ') + 1);
164
+ }
165
+ if (name.startsWith('.')) {
166
+ name = name.substring(1);
167
+ }
168
+ return name;
169
+ };
170
+
151
171
  export const getConfigFields = (rawFields, contextClass, primaryFieldsViewIndex) => {
152
172
  let primaryFields: any = [];
153
173
  let configFields: any = [];
174
+ const safeRawFields = rawFields || [];
154
175
 
155
176
  if (primaryFieldsViewIndex > -1) {
156
- let primaryFieldVMD: any = PCore.getMetadataUtils().resolveView(PRIMARY_FIELDS);
177
+ let primaryFieldVMD: any = PCore.getMetadataUtils().resolveView(getQualifiedPrimaryFieldsName());
157
178
  if (Array.isArray(primaryFieldVMD)) {
158
179
  primaryFieldVMD = primaryFieldVMD.find(primaryFieldView => primaryFieldView.classID === contextClass);
159
180
  primaryFields = primaryFieldVMD?.children?.[0]?.children || [];
@@ -166,7 +187,7 @@ export const getConfigFields = (rawFields, contextClass, primaryFieldsViewIndex)
166
187
  }
167
188
  }
168
189
 
169
- configFields = [...rawFields.slice(0, primaryFieldsViewIndex), ...primaryFields, ...rawFields.slice(primaryFieldsViewIndex + 1)];
190
+ configFields = [...safeRawFields.slice(0, primaryFieldsViewIndex), ...primaryFields, ...safeRawFields.slice(primaryFieldsViewIndex + 1)];
170
191
  // filter duplicate fields after combining raw fields and primary fields
171
192
  return configFields.filter((field, index) => configFields.findIndex(_field => field.config?.value === _field.config?.value) === index);
172
193
  };
@@ -195,12 +216,62 @@ export function getFieldLabel(fieldConfig) {
195
216
  return fieldLabel;
196
217
  }
197
218
 
219
+ function trimAnnotation(anno) {
220
+ if (typeof anno !== 'string' || !anno.startsWith('@')) return anno;
221
+ const spaceIndex = anno.indexOf(' ');
222
+ if (spaceIndex === -1) return anno;
223
+ return anno.substring(spaceIndex + 1);
224
+ }
225
+
226
+ /**
227
+ * Resolves an "@FL" label from the data model and localizes it using the property's locale reference.
228
+ */
229
+ function getLocalizedFieldLabel(fieldConfig, pConnect) {
230
+ const { classID, label, caption } = fieldConfig;
231
+ let fieldLabel = getPropertyNameFromConfigValue(label || caption);
232
+ const fieldMetaData: any = PCore.getMetadataUtils().getEmbeddedPropertyMetadata(fieldLabel, classID) ?? {};
233
+ fieldLabel = fieldMetaData.label ?? fieldMetaData.caption ?? fieldLabel;
234
+ const localeValue = pConnect.getLocalizationService(fieldMetaData.localeReference).getLocalizedText(fieldLabel);
235
+ return localeValue || fieldLabel;
236
+ }
237
+
238
+ export function resolveFieldLabel(fieldViewMetadata, pConnect, classID?) {
239
+ const fieldClassID = classID || fieldViewMetadata.config.classID;
240
+ if (fieldClassID && pConnect) {
241
+ const fieldConfig: any = {
242
+ meta: fieldViewMetadata,
243
+ options: {
244
+ ...pConnect.options,
245
+ hasForm: false,
246
+ localeReference: pConnect.getLocaleRuleName()
247
+ },
248
+ useCustomContext: { classID: fieldClassID }
249
+ };
250
+ const fieldPConnect = PCore.createPConnect(fieldConfig).getPConnect();
251
+ const resolvedProps: any = fieldPConnect.resolveConfigProps({
252
+ label: fieldViewMetadata.config.label || fieldViewMetadata.config.caption
253
+ });
254
+ if (resolvedProps.label) return resolvedProps.label;
255
+ }
256
+
257
+ let label = fieldViewMetadata.config.label || fieldViewMetadata.config.caption;
258
+ if (isFLProperty(label)) {
259
+ label = getLocalizedFieldLabel(fieldViewMetadata.config, pConnect);
260
+ } else {
261
+ label = trimAnnotation(label);
262
+ }
263
+ if (pConnect) {
264
+ label = pConnect.getLocalizedValue(label);
265
+ }
266
+ return label;
267
+ }
268
+
198
269
  export const updateFieldLabels = (fields, configFields, primaryFieldsViewIndex, pConnect, options) => {
199
270
  const labelsOfFields: any = [];
200
271
  const { columnsRawConfig = [] } = options;
201
272
  fields.forEach((field, idx) => {
202
273
  const rawColumnConfig = columnsRawConfig[idx]?.config;
203
- if (field.config.value === PRIMARY_FIELDS) {
274
+ if (isPrimaryFieldsValue(field.config.value)) {
204
275
  labelsOfFields.push('');
205
276
  } else if (isFLProperty(rawColumnConfig?.label ?? rawColumnConfig?.caption)) {
206
277
  labelsOfFields.push(getFieldLabel(rawColumnConfig) || field.config.label || field.config.caption);
@@ -217,7 +288,7 @@ export const updateFieldLabels = (fields, configFields, primaryFieldsViewIndex,
217
288
  let label = configFields[i].config?.label;
218
289
  if (isFLProperty(label)) {
219
290
  label = getFieldLabel(configFields[i].config);
220
- } else if (label.startsWith('@')) {
291
+ } else if (label?.startsWith('@')) {
221
292
  label = label.substring(3);
222
293
  }
223
294
  if (pConnect) {
@@ -233,13 +304,10 @@ export const updateFieldLabels = (fields, configFields, primaryFieldsViewIndex,
233
304
  return labelsOfFields;
234
305
  };
235
306
 
236
- export const buildFieldsForTable = (configFields, pConnect, showDeleteButton, options) => {
237
- const { primaryFieldsViewIndex, fields } = options;
307
+ export const buildFieldsForTable = (configFields, pConnect, showActionColumn, options) => {
308
+ const { classID } = options;
238
309
 
239
- // get resolved field labels for primary fields raw config included in configFields
240
- const fieldsLabels = updateFieldLabels(fields, configFields, primaryFieldsViewIndex, pConnect, {
241
- columnsRawConfig: pConnect.getRawConfigProps()?.children?.find(item => item?.name === 'Columns')?.children
242
- });
310
+ const fieldsLabels = configFields?.map(field => resolveFieldLabel(field, pConnect, classID)) ?? [];
243
311
 
244
312
  const fieldDefs = configFields?.map((field, index) => {
245
313
  return {
@@ -247,7 +315,7 @@ export const buildFieldsForTable = (configFields, pConnect, showDeleteButton, op
247
315
  label: fieldsLabels[index],
248
316
  fillAvailableSpace: !!field.config.fillAvailableSpace,
249
317
  id: `${index}`,
250
- name: field.config.value.substr(4),
318
+ name: getPropertyNameFromConfigValue(field.config.value),
251
319
  cellRenderer: TABLE_CELL,
252
320
  sort: false,
253
321
  noContextMenu: true,
@@ -256,12 +324,12 @@ export const buildFieldsForTable = (configFields, pConnect, showDeleteButton, op
256
324
  ...field
257
325
  },
258
326
  // BUG-615253: Workaround for autosize in table with lazy loading components
259
- width: getFieldWidth(field, fields[index].config.label)
327
+ width: getFieldWidth(field, fieldsLabels[index])
260
328
  };
261
329
  });
262
330
 
263
- // ONLY add DELETE_ICON to fields when the table is requested as EDITABLE
264
- if (showDeleteButton) {
331
+ // Add the action column when either edit or delete is available.
332
+ if (showActionColumn) {
265
333
  fieldDefs.push({
266
334
  type: 'text',
267
335
  label: '',
@@ -354,8 +422,8 @@ export const filterDataByDate = (item, filterObj) => {
354
422
 
355
423
  export const filterDataByCommonFields = (item, filterObj) => {
356
424
  let bKeep = true;
357
- const value = item[filterObj.ref].toLowerCase();
358
- const filterValue = filterObj.containsFilterValue.toLowerCase();
425
+ const value = String(item?.[filterObj.ref] ?? '').toLowerCase();
426
+ const filterValue = String(filterObj.containsFilterValue ?? '').toLowerCase();
359
427
 
360
428
  switch (filterObj.containsFilter) {
361
429
  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>
@@ -95,9 +113,7 @@
95
113
  </tr>
96
114
  </table>
97
115
  </div>
98
- <button *ngIf="showAddRowButton" mat-button color="primary" style="font-size: 16px" (click)="addRecord()">
99
- + {{ localizedVal('Add', localeCategory) }}
100
- </button>
116
+ <button *ngIf="showAddRowButton" mat-button color="primary" style="font-size: 16px" (click)="addRecord()">+ {{ addButtonLabel$ }}</button>
101
117
  </ng-container>
102
118
 
103
119
  <!-- pop overs for filters-->
@@ -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 {
@@ -163,6 +165,10 @@ tr.mat-mdc-header-row {
163
165
  text-align: center;
164
166
  border: 1px solid var(--mat-sys-outline-variant);
165
167
  border-top: none;
168
+
169
+ td.mat-cell {
170
+ text-align: center;
171
+ }
166
172
  }
167
173
 
168
174
  .psdk-utility-card-action-svg-icon {
@@ -17,7 +17,7 @@ import { ComponentMapperComponent } from '@pega/angular-sdk-components';
17
17
  import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
18
18
  import { DatapageService } from '@pega/angular-sdk-components';
19
19
  import { getReferenceList } from '@pega/angular-sdk-components';
20
- import { buildFieldsForTable, filterDataByCommonFields, filterDataByDate, getContext } from './helpers';
20
+ import { buildFieldsForTable, filterDataByCommonFields, filterDataByDate, getConfigFields, getContext, isPrimaryFieldsValue } from './helpers';
21
21
  import { evaluateAllowRowAction } from '@pega/angular-sdk-components';
22
22
  import { Utils } from '@pega/angular-sdk-components';
23
23
  import { getSeconds } from '@pega/angular-sdk-components';
@@ -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;
@@ -46,7 +47,8 @@ interface SimpleTableManualProps {
46
47
  displayMode?: string;
47
48
  useSeparateViewForEdit: any;
48
49
  viewForEditModal: any;
49
- targetClassLabel: string;
50
+ targetClassLabel?: string;
51
+ uniqueField?: string;
50
52
  }
51
53
 
52
54
  class Group {
@@ -59,6 +61,12 @@ class Group {
59
61
  }
60
62
  }
61
63
 
64
+ interface RowActions {
65
+ canEdit: boolean;
66
+ canDelete: boolean;
67
+ hasAnyAction: boolean;
68
+ }
69
+
62
70
  @Component({
63
71
  selector: 'app-simple-table-manual',
64
72
  templateUrl: './simple-table-manual.component.html',
@@ -92,7 +100,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
92
100
 
93
101
  bVisible$ = true;
94
102
  displayedColumns: string[] = [];
95
- rowData: MatTableDataSource<any>;
103
+ rowData = new MatTableDataSource<any>([]);
96
104
  originalData: any[] = [];
97
105
  processedFields: any[] = [];
98
106
  fieldDefs: any[] = [];
@@ -108,6 +116,9 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
108
116
  elementsData: MatTableDataSource<any>;
109
117
  originalElementsData: MatTableDataSource<any>;
110
118
  rawFields: any;
119
+ configFields: any[] = [];
120
+ uniqueField?: string;
121
+ normalizedUniqueField?: string;
111
122
  label?: string = '';
112
123
  searchIcon$: string;
113
124
 
@@ -159,15 +170,22 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
159
170
  referenceListStr: any;
160
171
  bUseSeparateViewForEdit: any;
161
172
  editView: any;
173
+ editType: any;
162
174
  defaultActionId: any;
163
175
  editActionId: any;
164
176
  settingsSvgIcon$: string;
165
177
 
166
178
  isInitialized = false;
167
- targetClassLabel: string;
179
+ targetClassLabel = '';
180
+ addButtonLabel$ = '';
168
181
  localizedVal = PCore.getLocaleUtils().getLocaleValue;
169
182
  localeCategory = 'SimpleTable';
170
- editType: any;
183
+ hideEditRow: any;
184
+ hideDeleteRow: boolean;
185
+ showEditButton: boolean;
186
+ showDeleteButton: boolean;
187
+ showActionColumn: boolean;
188
+ rowActions: RowActions[] = [];
171
189
  constructor(
172
190
  private angularPConnect: AngularPConnectService,
173
191
  public utils: Utils,
@@ -238,7 +256,6 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
238
256
  presets,
239
257
  allowActions,
240
258
  allowTableEdit,
241
- allowRowDelete,
242
259
  label: labelProp,
243
260
  propertyLabel,
244
261
  fieldMetadata,
@@ -249,9 +266,15 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
249
266
  displayMode,
250
267
  useSeparateViewForEdit,
251
268
  viewForEditModal,
252
- targetClassLabel
269
+ targetClassLabel,
270
+ uniqueField
253
271
  } = this.configProps$;
254
272
 
273
+ // uniqueField is authored as a property reference (ex: ".EmbedListUUID__"); page instructions expect it
274
+ // with the leading dot while the inserted row payload expects the bare property name.
275
+ this.uniqueField = uniqueField;
276
+ this.normalizedUniqueField = uniqueField?.startsWith('.') ? uniqueField.substring(1) : uniqueField;
277
+
255
278
  const simpleTableManualProps: any = {};
256
279
  if (this.checkIfAllowActionsOrRowEditingExist(allowActions) && editMode) {
257
280
  simpleTableManualProps.hideAddRow = allowActions?.allowAdd === false;
@@ -267,7 +290,8 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
267
290
  this.referenceListStr = getContext(this.pConn$).referenceListStr;
268
291
  this.label = labelProp || propertyLabel;
269
292
  this.parameters = fieldMetadata?.datasource?.parameters;
270
- this.targetClassLabel = targetClassLabel;
293
+ this.targetClassLabel = targetClassLabel ?? '';
294
+ this.addButtonLabel$ = this.getAddButtonLabel();
271
295
  let { contextClass } = this.configProps$;
272
296
  this.referenceList = referenceList;
273
297
  if (!contextClass) {
@@ -304,10 +328,16 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
304
328
  this.readOnlyMode = renderMode === 'ReadOnly';
305
329
  this.editableMode = renderMode === 'Editable';
306
330
  const isDisplayModeEnabled = displayMode === 'DISPLAY_ONLY';
307
- this.showAddRowButton = !this.readOnlyMode && !simpleTableManualProps.hideAddRow;
331
+ this.showAddRowButton = this.getShowAddRowButton(simpleTableManualProps.hideAddRow);
332
+ this.hideEditRow = simpleTableManualProps.hideEditRow;
333
+ this.hideDeleteRow = simpleTableManualProps.hideDeleteRow;
308
334
  this.allowEditingInModal =
309
335
  (editMode ? editMode === 'modal' : addAndEditRowsWithin === 'modal') && !(renderMode === 'ReadOnly' || isDisplayModeEnabled);
310
- const showDeleteButton = this.editableMode && !simpleTableManualProps.hideDeleteRow && evaluateAllowRowAction(allowRowDelete, this.rowData);
336
+ this.showEditButton = this.allowEditingInModal && !this.hideEditRow;
337
+ this.showDeleteButton = this.editableMode && !this.hideDeleteRow;
338
+ this.showActionColumn = this.showEditButton || this.showDeleteButton;
339
+ const { allowRowEdit, allowRowDelete } = this.pConn$.getComponentConfig?.() ?? {};
340
+ this.rowActions = this.referenceList.map(row => this.getRowActions(row, allowRowEdit, allowRowDelete));
311
341
  this.defaultView = editModeConfig ? editModeConfig.defaultView : viewForAddAndEditModal;
312
342
  this.bUseSeparateViewForEdit = editModeConfig ? editModeConfig.useSeparateViewForEdit : useSeparateViewForEdit;
313
343
  this.editView = editModeConfig ? editModeConfig.editView : viewForEditModal;
@@ -315,9 +345,14 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
315
345
  this.defaultActionId = this.editType === 'action' ? editModeConfig?.defaultAction : undefined;
316
346
  this.editActionId =
317
347
  this.editType === 'action' && editModeConfig?.useSeparateActionForEdit ? editModeConfig?.editAction : editModeConfig?.defaultAction;
318
- const primaryFieldsViewIndex = resolvedFields.findIndex(field => field.config.value === 'pyPrimaryFields');
348
+ const primaryFieldsViewIndex = resolvedFields?.findIndex(field => isPrimaryFieldsValue(field.config.value)) ?? -1;
319
349
  // const showDeleteButton = !this.readOnlyMode && !hideDeleteRow;
320
350
 
351
+ // "pyPrimaryFields" is a single authored column that expands into several real columns, so the
352
+ // resolved/raw children can no longer be used directly - configFields is the expanded column list.
353
+ const configFields = getConfigFields(rawFields, contextClass, primaryFieldsViewIndex);
354
+ this.configFields = configFields.filter(field => !(field?.config?.hide === true));
355
+
321
356
  // Nebula has other handling for isReadOnlyMode but has Cosmos-specific code
322
357
  // so ignoring that for now...
323
358
  // fieldDefs will be an array where each entry will have a "name" which will be the
@@ -326,9 +361,10 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
326
361
  // Nebula does). It will also have the "label", and "meta" contains the original,
327
362
  // unchanged config info. For now, much of the info here is carried over from
328
363
  // Nebula and we may not end up using it all.
329
- this.fieldDefs = buildFieldsForTable(rawFields, this.pConn$, showDeleteButton, {
364
+ this.fieldDefs = buildFieldsForTable(configFields, this.pConn$, this.showActionColumn, {
330
365
  primaryFieldsViewIndex,
331
- fields: resolvedFields
366
+ fields: resolvedFields,
367
+ classID: contextClass
332
368
  });
333
369
  this.fieldDefs = this.fieldDefs?.filter(field => !(field.meta?.config?.hide === true));
334
370
  this.initializeDefaultPageInstructions();
@@ -342,7 +378,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
342
378
  return field.name ? field.name : field.cellRenderer;
343
379
  });
344
380
 
345
- // And now we can process the resolvedFields to add in the "name"
381
+ // And now we can process the configFields to add in the "name"
346
382
  // from from the fieldDefs. This "name" is the value that
347
383
  // we'll share to connect things together in the table.
348
384
 
@@ -350,12 +386,9 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
350
386
  return { ...acc, [curr.name]: curr.label };
351
387
  }, {});
352
388
 
353
- this.processedFields = [];
354
-
355
- this.processedFields = resolvedFields.map((field, i) => {
356
- field.config.name = this.displayedColumns[i]; // .config["value"].replace(/ ./g,"_"); // replace space dot with underscore
357
- field.config.label = labelsMap[field.config.name] || field.config.label;
358
- return field;
389
+ this.processedFields = this.configFields.map((field, i) => {
390
+ const name = this.displayedColumns[i];
391
+ return { ...field, config: { ...field.config, name, label: labelsMap[name] || field.config.label } };
359
392
  });
360
393
 
361
394
  // for adding rows to table when editable and not modal view
@@ -364,7 +397,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
364
397
  }
365
398
 
366
399
  // for edit and adding rows in modal view and to generate readonly list
367
- if (!isEqual(this.prevReferenceList, this.referenceList) && (this.readOnlyMode || this.allowEditingInModal)) {
400
+ if (!isEqual(this.prevReferenceList, this.referenceList) && (this.readOnlyMode || this.allowEditingInModal || this.hideEditRow)) {
368
401
  this.generateRowsData();
369
402
  }
370
403
 
@@ -391,17 +424,22 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
391
424
  }
392
425
 
393
426
  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
- }
427
+ if (!this.isInitialized) {
428
+ return;
429
+ }
430
+
431
+ this.isInitialized = false;
432
+
433
+ if (this.allowEditingInModal) {
434
+ this.pConn$.getListActions().initDefaultPageInstructions(
435
+ this.pConn$.getReferenceList(),
436
+ // Temporary filter for attachments to align with constellation payload behavior.
437
+ this.fieldDefs.filter(item => item.name && item.meta?.type !== 'Attachment').map(item => item.name),
438
+ this.uniqueField
439
+ );
440
+ } else {
441
+ // @ts-ignore - 'propertyNames' is optional at runtime; uniqueField is passed as the 3rd argument.
442
+ this.pConn$.getListActions().initDefaultPageInstructions(this.pConn$.getReferenceList(), undefined, this.uniqueField);
405
443
  }
406
444
  }
407
445
 
@@ -410,6 +448,30 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
410
448
  return `${recordsCount || 0} result${recordsCount > 1 ? 's' : ''}`;
411
449
  }
412
450
 
451
+ private getRowActions(row: any, allowRowEdit: any, allowRowDelete: any): RowActions {
452
+ const canEdit = this.showEditButton && evaluateAllowRowAction(allowRowEdit, row);
453
+ const canDelete = this.showDeleteButton && this.isDeleteAllowedForRow(row, allowRowDelete);
454
+
455
+ return {
456
+ canEdit,
457
+ canDelete,
458
+ hasAnyAction: canEdit || canDelete
459
+ };
460
+ }
461
+
462
+ private isDeleteAllowedForRow(row: any, allowRowDelete: any): boolean {
463
+ if (allowRowDelete === undefined || allowRowDelete === true) return true;
464
+ if (typeof allowRowDelete === 'string' && allowRowDelete.startsWith('@E ')) {
465
+ try {
466
+ const expression = allowRowDelete.replace('@E ', '');
467
+ return PCore.getExpressionEngine().evaluate(expression, row);
468
+ } catch {
469
+ return true;
470
+ }
471
+ }
472
+ return false;
473
+ }
474
+
413
475
  sortCompare(a, b): number {
414
476
  let aValue = a[0][this.compareRef];
415
477
  let bValue = b[0][this.compareRef];
@@ -909,11 +971,10 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
909
971
  }
910
972
 
911
973
  _getIconStyle(level): string {
912
- let sReturn = '';
913
974
  let nLevel = parseInt(level, 10);
914
975
  nLevel--;
915
976
  nLevel *= 15;
916
- sReturn = `padding-left: ${nLevel}px; vertical-align: middle`;
977
+ const sReturn = `padding-left: ${nLevel}px; vertical-align: middle`;
917
978
 
918
979
  return sReturn;
919
980
  }
@@ -929,9 +990,13 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
929
990
  // See what data (if any) we have to display
930
991
  const refKeys: string[] = inColKey.split('.');
931
992
  let valBuilder = inRowData;
993
+ let index = 0;
994
+
932
995
  for (const key of refKeys) {
933
- valBuilder = valBuilder[key] ? valBuilder[key] : valBuilder;
996
+ index += 1;
997
+ valBuilder = valBuilder[key] !== undefined || index === refKeys.length ? valBuilder[key] : valBuilder;
934
998
  }
999
+
935
1000
  return valBuilder;
936
1001
  }
937
1002
 
@@ -979,7 +1044,11 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
979
1044
  this.defaultActionId
980
1045
  );
981
1046
  } else {
982
- this.pConn$.getListActions().insert({ classID: this.contextClass }, this.referenceList.length);
1047
+ const payload: any = { classID: this.contextClass };
1048
+ if (this.normalizedUniqueField) {
1049
+ payload[this.normalizedUniqueField] = crypto.randomUUID();
1050
+ }
1051
+ this.pConn$.getListActions().insert(payload, this.referenceList.length);
983
1052
  }
984
1053
 
985
1054
  this.pConn$.clearErrorMessages({
@@ -987,39 +1056,58 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
987
1056
  });
988
1057
  }
989
1058
 
1059
+ getAddButtonLabel(): string {
1060
+ const addLabel = this.targetClassLabel
1061
+ ? this.localizedVal('Add {0}', this.localeCategory).replace('{0}', this.targetClassLabel)
1062
+ : this.localizedVal('Add', this.localeCategory);
1063
+
1064
+ return this.localizedVal(addLabel, this.localeCategory);
1065
+ }
1066
+
1067
+ getShowAddRowButton(hideAddRow?: boolean): boolean {
1068
+ return !this.readOnlyMode && !hideAddRow;
1069
+ }
1070
+
990
1071
  editRecord(data, index) {
991
- if (data) {
1072
+ if (data && Number.isInteger(index) && index >= 0 && index < this.referenceList.length) {
1073
+ const viewForEdit = this.bUseSeparateViewForEdit ? this.editView : this.defaultView;
992
1074
  this.pConn$
993
1075
  .getActionsApi()
994
- // @ts-expect-error
995
1076
  .openEmbeddedDataModal(
996
- this.bUseSeparateViewForEdit ? this.editView : this.defaultView,
1077
+ viewForEdit,
997
1078
  this.pConn$ as any,
998
1079
  this.referenceListStr,
999
1080
  index,
1000
1081
  PCore.getConstants().RESOURCE_STATUS.UPDATE,
1001
- this.targetClassLabel
1082
+ this.targetClassLabel,
1083
+ this.editType,
1084
+ this.editActionId
1002
1085
  );
1003
1086
  }
1004
1087
  }
1005
1088
 
1006
1089
  deleteRecord(index) {
1007
- this.pConn$.getListActions().deleteEntry(index);
1090
+ if (Number.isInteger(index) && index >= 0 && index < this.referenceList.length) {
1091
+ this.pConn$.getListActions().deleteEntry(index);
1092
+ }
1008
1093
  }
1009
1094
 
1010
1095
  buildElementsForTable() {
1011
1096
  const context = this.pConn$.getContextName();
1097
+ const { allowRowEdit } = this.pConn$.getComponentConfig?.() ?? {};
1012
1098
  const eleData: any = [];
1013
1099
  this.referenceList.forEach((element, index) => {
1100
+ const isRowEditable = evaluateAllowRowAction(allowRowEdit, element);
1014
1101
  const data: any = [];
1015
- this.rawFields?.forEach(item => {
1102
+ data.__originalIndex = index;
1103
+ this.configFields?.forEach(item => {
1016
1104
  if (!item?.config?.hide) {
1017
1105
  item = {
1018
1106
  ...item,
1019
1107
  config: {
1020
1108
  ...item.config,
1021
1109
  label: '',
1022
- displayMode: this.readOnlyMode || this.allowEditingInModal ? 'DISPLAY_ONLY' : undefined
1110
+ displayMode: this.readOnlyMode || this.allowEditingInModal || this.hideEditRow || !isRowEditable ? 'DISPLAY_ONLY' : undefined
1023
1111
  }
1024
1112
  };
1025
1113
  const referenceListData = getReferenceList(this.pConn$);