@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
@@ -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,12 +170,22 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
159
170
  referenceListStr: any;
160
171
  bUseSeparateViewForEdit: any;
161
172
  editView: any;
173
+ editType: any;
174
+ defaultActionId: any;
175
+ editActionId: any;
162
176
  settingsSvgIcon$: string;
163
177
 
164
178
  isInitialized = false;
165
- targetClassLabel: string;
179
+ targetClassLabel = '';
180
+ addButtonLabel$ = '';
166
181
  localizedVal = PCore.getLocaleUtils().getLocaleValue;
167
182
  localeCategory = 'SimpleTable';
183
+ hideEditRow: any;
184
+ hideDeleteRow: boolean;
185
+ showEditButton: boolean;
186
+ showDeleteButton: boolean;
187
+ showActionColumn: boolean;
188
+ rowActions: RowActions[] = [];
168
189
  constructor(
169
190
  private angularPConnect: AngularPConnectService,
170
191
  public utils: Utils,
@@ -235,7 +256,6 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
235
256
  presets,
236
257
  allowActions,
237
258
  allowTableEdit,
238
- allowRowDelete,
239
259
  label: labelProp,
240
260
  propertyLabel,
241
261
  fieldMetadata,
@@ -246,9 +266,15 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
246
266
  displayMode,
247
267
  useSeparateViewForEdit,
248
268
  viewForEditModal,
249
- targetClassLabel
269
+ targetClassLabel,
270
+ uniqueField
250
271
  } = this.configProps$;
251
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
+
252
278
  const simpleTableManualProps: any = {};
253
279
  if (this.checkIfAllowActionsOrRowEditingExist(allowActions) && editMode) {
254
280
  simpleTableManualProps.hideAddRow = allowActions?.allowAdd === false;
@@ -264,7 +290,8 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
264
290
  this.referenceListStr = getContext(this.pConn$).referenceListStr;
265
291
  this.label = labelProp || propertyLabel;
266
292
  this.parameters = fieldMetadata?.datasource?.parameters;
267
- this.targetClassLabel = targetClassLabel;
293
+ this.targetClassLabel = targetClassLabel ?? '';
294
+ this.addButtonLabel$ = this.getAddButtonLabel();
268
295
  let { contextClass } = this.configProps$;
269
296
  this.referenceList = referenceList;
270
297
  if (!contextClass) {
@@ -301,16 +328,31 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
301
328
  this.readOnlyMode = renderMode === 'ReadOnly';
302
329
  this.editableMode = renderMode === 'Editable';
303
330
  const isDisplayModeEnabled = displayMode === 'DISPLAY_ONLY';
304
- this.showAddRowButton = !this.readOnlyMode && !simpleTableManualProps.hideAddRow;
331
+ this.showAddRowButton = this.getShowAddRowButton(simpleTableManualProps.hideAddRow);
332
+ this.hideEditRow = simpleTableManualProps.hideEditRow;
333
+ this.hideDeleteRow = simpleTableManualProps.hideDeleteRow;
305
334
  this.allowEditingInModal =
306
335
  (editMode ? editMode === 'modal' : addAndEditRowsWithin === 'modal') && !(renderMode === 'ReadOnly' || isDisplayModeEnabled);
307
- 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));
308
341
  this.defaultView = editModeConfig ? editModeConfig.defaultView : viewForAddAndEditModal;
309
342
  this.bUseSeparateViewForEdit = editModeConfig ? editModeConfig.useSeparateViewForEdit : useSeparateViewForEdit;
310
343
  this.editView = editModeConfig ? editModeConfig.editView : viewForEditModal;
311
- const primaryFieldsViewIndex = resolvedFields.findIndex(field => field.config.value === 'pyPrimaryFields');
344
+ this.editType = editModeConfig?.editType;
345
+ this.defaultActionId = this.editType === 'action' ? editModeConfig?.defaultAction : undefined;
346
+ this.editActionId =
347
+ this.editType === 'action' && editModeConfig?.useSeparateActionForEdit ? editModeConfig?.editAction : editModeConfig?.defaultAction;
348
+ const primaryFieldsViewIndex = resolvedFields?.findIndex(field => isPrimaryFieldsValue(field.config.value)) ?? -1;
312
349
  // const showDeleteButton = !this.readOnlyMode && !hideDeleteRow;
313
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
+
314
356
  // Nebula has other handling for isReadOnlyMode but has Cosmos-specific code
315
357
  // so ignoring that for now...
316
358
  // fieldDefs will be an array where each entry will have a "name" which will be the
@@ -319,9 +361,10 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
319
361
  // Nebula does). It will also have the "label", and "meta" contains the original,
320
362
  // unchanged config info. For now, much of the info here is carried over from
321
363
  // Nebula and we may not end up using it all.
322
- this.fieldDefs = buildFieldsForTable(rawFields, this.pConn$, showDeleteButton, {
364
+ this.fieldDefs = buildFieldsForTable(configFields, this.pConn$, this.showActionColumn, {
323
365
  primaryFieldsViewIndex,
324
- fields: resolvedFields
366
+ fields: resolvedFields,
367
+ classID: contextClass
325
368
  });
326
369
  this.fieldDefs = this.fieldDefs?.filter(field => !(field.meta?.config?.hide === true));
327
370
  this.initializeDefaultPageInstructions();
@@ -335,7 +378,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
335
378
  return field.name ? field.name : field.cellRenderer;
336
379
  });
337
380
 
338
- // 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"
339
382
  // from from the fieldDefs. This "name" is the value that
340
383
  // we'll share to connect things together in the table.
341
384
 
@@ -343,12 +386,9 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
343
386
  return { ...acc, [curr.name]: curr.label };
344
387
  }, {});
345
388
 
346
- this.processedFields = [];
347
-
348
- this.processedFields = resolvedFields.map((field, i) => {
349
- field.config.name = this.displayedColumns[i]; // .config["value"].replace(/ ./g,"_"); // replace space dot with underscore
350
- field.config.label = labelsMap[field.config.name] || field.config.label;
351
- 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 } };
352
392
  });
353
393
 
354
394
  // for adding rows to table when editable and not modal view
@@ -357,7 +397,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
357
397
  }
358
398
 
359
399
  // for edit and adding rows in modal view and to generate readonly list
360
- if (!isEqual(this.prevReferenceList, this.referenceList) && (this.readOnlyMode || this.allowEditingInModal)) {
400
+ if (!isEqual(this.prevReferenceList, this.referenceList) && (this.readOnlyMode || this.allowEditingInModal || this.hideEditRow)) {
361
401
  this.generateRowsData();
362
402
  }
363
403
 
@@ -384,17 +424,22 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
384
424
  }
385
425
 
386
426
  initializeDefaultPageInstructions() {
387
- if (this.isInitialized) {
388
- this.isInitialized = false;
389
- if (this.allowEditingInModal) {
390
- this.pConn$.getListActions().initDefaultPageInstructions(
391
- this.pConn$.getReferenceList(),
392
- this.fieldDefs.filter(item => item.name).map(item => item.name)
393
- );
394
- } else {
395
- // @ts-ignore - An argument for 'propertyNames' was not provided.
396
- this.pConn$.getListActions().initDefaultPageInstructions(this.pConn$.getReferenceList());
397
- }
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);
398
443
  }
399
444
  }
400
445
 
@@ -403,6 +448,30 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
403
448
  return `${recordsCount || 0} result${recordsCount > 1 ? 's' : ''}`;
404
449
  }
405
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
+
406
475
  sortCompare(a, b): number {
407
476
  let aValue = a[0][this.compareRef];
408
477
  let bValue = b[0][this.compareRef];
@@ -902,11 +971,10 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
902
971
  }
903
972
 
904
973
  _getIconStyle(level): string {
905
- let sReturn = '';
906
974
  let nLevel = parseInt(level, 10);
907
975
  nLevel--;
908
976
  nLevel *= 15;
909
- sReturn = `padding-left: ${nLevel}px; vertical-align: middle`;
977
+ const sReturn = `padding-left: ${nLevel}px; vertical-align: middle`;
910
978
 
911
979
  return sReturn;
912
980
  }
@@ -922,9 +990,13 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
922
990
  // See what data (if any) we have to display
923
991
  const refKeys: string[] = inColKey.split('.');
924
992
  let valBuilder = inRowData;
993
+ let index = 0;
994
+
925
995
  for (const key of refKeys) {
926
- valBuilder = valBuilder[key];
996
+ index += 1;
997
+ valBuilder = valBuilder[key] !== undefined || index === refKeys.length ? valBuilder[key] : valBuilder;
927
998
  }
999
+
928
1000
  return valBuilder;
929
1001
  }
930
1002
 
@@ -958,20 +1030,25 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
958
1030
  }
959
1031
 
960
1032
  addRecord() {
961
- if (this.allowEditingInModal && this.defaultView) {
1033
+ if (this.allowEditingInModal && (this.defaultView || this.defaultActionId)) {
962
1034
  this.pConn$
963
1035
  .getActionsApi()
964
- // @ts-expect-error
965
1036
  .openEmbeddedDataModal(
966
1037
  this.defaultView,
967
1038
  this.pConn$ as any,
968
1039
  this.referenceListStr,
969
1040
  this.referenceList.length,
970
1041
  PCore.getConstants().RESOURCE_STATUS.CREATE,
971
- this.targetClassLabel
1042
+ this.targetClassLabel,
1043
+ this.editType,
1044
+ this.defaultActionId
972
1045
  );
973
1046
  } else {
974
- 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);
975
1052
  }
976
1053
 
977
1054
  this.pConn$.clearErrorMessages({
@@ -979,46 +1056,65 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
979
1056
  });
980
1057
  }
981
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
+
982
1071
  editRecord(data, index) {
983
- if (data) {
1072
+ if (data && Number.isInteger(index) && index >= 0 && index < this.referenceList.length) {
1073
+ const viewForEdit = this.bUseSeparateViewForEdit ? this.editView : this.defaultView;
984
1074
  this.pConn$
985
1075
  .getActionsApi()
986
- // @ts-expect-error
987
1076
  .openEmbeddedDataModal(
988
- this.bUseSeparateViewForEdit ? this.editView : this.defaultView,
1077
+ viewForEdit,
989
1078
  this.pConn$ as any,
990
1079
  this.referenceListStr,
991
1080
  index,
992
1081
  PCore.getConstants().RESOURCE_STATUS.UPDATE,
993
- this.targetClassLabel
1082
+ this.targetClassLabel,
1083
+ this.editType,
1084
+ this.editActionId
994
1085
  );
995
1086
  }
996
1087
  }
997
1088
 
998
1089
  deleteRecord(index) {
999
- this.pConn$.getListActions().deleteEntry(index);
1090
+ if (Number.isInteger(index) && index >= 0 && index < this.referenceList.length) {
1091
+ this.pConn$.getListActions().deleteEntry(index);
1092
+ }
1000
1093
  }
1001
1094
 
1002
1095
  buildElementsForTable() {
1003
1096
  const context = this.pConn$.getContextName();
1097
+ const { allowRowEdit } = this.pConn$.getComponentConfig?.() ?? {};
1004
1098
  const eleData: any = [];
1005
1099
  this.referenceList.forEach((element, index) => {
1100
+ const isRowEditable = evaluateAllowRowAction(allowRowEdit, element);
1006
1101
  const data: any = [];
1007
- this.rawFields?.forEach(item => {
1102
+ data.__originalIndex = index;
1103
+ this.configFields?.forEach(item => {
1008
1104
  if (!item?.config?.hide) {
1009
1105
  item = {
1010
1106
  ...item,
1011
1107
  config: {
1012
1108
  ...item.config,
1013
1109
  label: '',
1014
- displayMode: this.readOnlyMode || this.allowEditingInModal ? 'DISPLAY_ONLY' : undefined
1110
+ displayMode: this.readOnlyMode || this.allowEditingInModal || this.hideEditRow || !isRowEditable ? 'DISPLAY_ONLY' : undefined
1015
1111
  }
1016
1112
  };
1017
1113
  const referenceListData = getReferenceList(this.pConn$);
1018
1114
  const isDatapage = referenceListData.startsWith('D_');
1019
1115
  const pageReferenceValue = isDatapage
1020
1116
  ? `${referenceListData}[${index}]`
1021
- : `${this.pConn$.getPageReference()}${referenceListData}[${index}]`;
1117
+ : `${this.pConn$.getPageReference()}${referenceListData.substring(referenceListData.lastIndexOf('.'))}[${index}]`;
1022
1118
  const config = {
1023
1119
  meta: item,
1024
1120
  options: {