@pega/angular-sdk-overrides 0.26.1 → 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 (74) 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 +8 -6
  11. package/lib/field/check-box/check-box.component.html +3 -1
  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/field.base.ts +27 -1
  27. package/lib/field/integer/integer.component.html +2 -1
  28. package/lib/field/integer/integer.component.ts +4 -2
  29. package/lib/field/location/location.component.html +2 -1
  30. package/lib/field/location/location.component.ts +3 -1
  31. package/lib/field/object-reference/object-reference.component.html +1 -1
  32. package/lib/field/object-reference/object-reference.component.ts +3 -0
  33. package/lib/field/percentage/percentage.component.html +2 -1
  34. package/lib/field/percentage/percentage.component.ts +10 -1
  35. package/lib/field/phone/phone.component.html +2 -1
  36. package/lib/field/phone/phone.component.ts +2 -1
  37. package/lib/field/radio-buttons/radio-buttons.component.html +2 -1
  38. package/lib/field/radio-buttons/radio-buttons.component.ts +10 -1
  39. package/lib/field/rich-text/rich-text.component.scss +1 -166
  40. package/lib/field/rich-text/rich-text.component.ts +1 -1
  41. package/lib/field/semantic-link/semantic-link.component.ts +9 -5
  42. package/lib/field/text-area/text-area.component.html +2 -1
  43. package/lib/field/text-area/text-area.component.ts +2 -1
  44. package/lib/field/text-input/text-input.component.html +2 -1
  45. package/lib/field/text-input/text-input.component.ts +2 -1
  46. package/lib/field/time/time.component.html +2 -1
  47. package/lib/field/time/time.component.ts +2 -1
  48. package/lib/field/url/url.component.html +2 -1
  49. package/lib/field/url/url.component.ts +2 -1
  50. package/lib/field/user-reference/user-reference.component.html +4 -2
  51. package/lib/field/user-reference/user-reference.component.ts +10 -5
  52. package/lib/infra/Containers/flow-container/flow-container.component.ts +33 -40
  53. package/lib/infra/Containers/modal-view-container/modal-view-container.component.ts +46 -50
  54. package/lib/infra/Containers/view-container/view-container.component.ts +32 -31
  55. package/lib/infra/navbar/navbar.component.ts +33 -35
  56. package/lib/infra/root-container/root-container.component.ts +33 -38
  57. package/lib/template/app-shell/app-shell.component.ts +12 -11
  58. package/lib/template/base/details-template-base.ts +2 -1
  59. package/lib/template/default-form/default-form.component.html +19 -3
  60. package/lib/template/default-form/default-form.component.ts +13 -3
  61. package/lib/template/simple-table-manual/helpers.ts +3 -3
  62. package/lib/template/simple-table-manual/simple-table-manual.component.html +29 -11
  63. package/lib/template/simple-table-manual/simple-table-manual.component.ts +69 -11
  64. package/lib/template/single-reference-readonly/single-reference-readonly.component.html +1 -1
  65. package/lib/template/single-reference-readonly/single-reference-readonly.component.scss +4 -0
  66. package/lib/template/single-reference-readonly/single-reference-readonly.component.ts +4 -4
  67. package/lib/template/wss-nav-bar/wss-nav-bar.component.ts +18 -20
  68. package/lib/widget/attachment/AttachmentUtils.ts +18 -10
  69. package/lib/widget/attachment/attachment.component.html +16 -6
  70. package/lib/widget/attachment/attachment.component.ts +12 -2
  71. package/lib/widget/case-history/case-history.component.ts +6 -2
  72. package/lib/widget/file-utility/file-utility.component.ts +25 -29
  73. package/lib/widget/todo/todo.component.ts +7 -2
  74. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { Component, OnInit, Input, ChangeDetectorRef, NgZone, OnDestroy } from '@angular/core';
1
+ import { Component, OnInit, Input, ChangeDetectorRef, OnDestroy } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { MatMenuModule } from '@angular/material/menu';
4
4
  import { MatListModule } from '@angular/material/list';
@@ -53,7 +53,6 @@ export class NavbarComponent implements OnInit, OnDestroy {
53
53
  private angularPConnect: AngularPConnectService,
54
54
  private chRef: ChangeDetectorRef,
55
55
  private psService: ProgressSpinnerService,
56
- private ngZone: NgZone,
57
56
  private utils: Utils
58
57
  ) {}
59
58
 
@@ -104,40 +103,39 @@ export class NavbarComponent implements OnInit, OnDestroy {
104
103
  }
105
104
 
106
105
  initComponent() {
107
- this.ngZone.run(() => {
108
- this.navIcon$ = this.utils.getSDKStaticContentUrl().concat('assets/pzpega-logo-mark.svg');
109
- this.navExpandCollapse$ = this.utils.getImageSrc('plus', this.utils.getSDKStaticContentUrl());
110
-
111
- // Then, continue on with other initialization
112
-
113
- // making a copy, so can add info
114
- this.navPages$ = JSON.parse(JSON.stringify(this.pages$));
115
- // @ts-ignore
116
- const localeReference = PCore.getLocaleUtils().getPortalLocaleReference() || this.pConn$.getValue('.pyLocaleReference');
117
- this.navPages$.forEach(page => {
118
- const destinationObject: any = {};
119
- this.pConn$.resolveConfigProps(
120
- { defaultHeading: page.pyDefaultHeading || page.pyLabel, localeReference: page.pyLocalizationReference },
121
- destinationObject
122
- );
123
- page.name = this.localeUtils.getLocaleValue(destinationObject.defaultHeading, '', destinationObject.localeReference || localeReference);
124
- page.iconName = this.utils.getImageSrc(page.pxPageViewIcon, this.utils.getSDKStaticContentUrl());
125
- });
126
- this.actionsAPI = this.pConn$.getActionsApi();
127
- this.createWork = this.actionsAPI.createWork.bind(this.actionsAPI);
128
- this.showPage = this.actionsAPI.showPage.bind(this.actionsAPI);
129
- this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as NavBarProps;
130
- this.logout = this.actionsAPI.logout.bind(this.actionsAPI);
131
-
132
- // const oData = this.pConn$.getDataObject();
133
-
134
- this.portalLogoImage$ = this.utils.getSDKStaticContentUrl().concat('assets/pzpega-logo-mark.svg');
135
- this.portalOperator$ = PCore.getEnvironmentInfo().getOperatorName();
136
- this.portalOperatorInitials$ = this.utils.getInitials(this.portalOperator$ ?? '');
137
- this.showAppName$ = this.configProps$.showAppName;
138
-
139
- this.portalApp$ = PCore.getEnvironmentInfo().getApplicationLabel();
106
+ this.navIcon$ = this.utils.getSDKStaticContentUrl().concat('assets/pzpega-logo-mark.svg');
107
+ this.navExpandCollapse$ = this.utils.getImageSrc('plus', this.utils.getSDKStaticContentUrl());
108
+
109
+ // Then, continue on with other initialization
110
+
111
+ // making a copy, so can add info
112
+ this.navPages$ = JSON.parse(JSON.stringify(this.pages$));
113
+ // @ts-ignore
114
+ const localeReference = PCore.getLocaleUtils().getPortalLocaleReference() || this.pConn$.getValue('.pyLocaleReference');
115
+ this.navPages$.forEach(page => {
116
+ const destinationObject: any = {};
117
+ this.pConn$.resolveConfigProps(
118
+ { defaultHeading: page.pyDefaultHeading || page.pyLabel, localeReference: page.pyLocalizationReference },
119
+ destinationObject
120
+ );
121
+ page.name = this.localeUtils.getLocaleValue(destinationObject.defaultHeading, '', destinationObject.localeReference || localeReference);
122
+ page.iconName = this.utils.getImageSrc(page.pxPageViewIcon, this.utils.getSDKStaticContentUrl());
140
123
  });
124
+ this.actionsAPI = this.pConn$.getActionsApi();
125
+ this.createWork = this.actionsAPI.createWork.bind(this.actionsAPI);
126
+ this.showPage = this.actionsAPI.showPage.bind(this.actionsAPI);
127
+ this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as NavBarProps;
128
+ this.logout = this.actionsAPI.logout.bind(this.actionsAPI);
129
+
130
+ // const oData = this.pConn$.getDataObject();
131
+
132
+ this.portalLogoImage$ = this.utils.getSDKStaticContentUrl().concat('assets/pzpega-logo-mark.svg');
133
+ this.portalOperator$ = PCore.getEnvironmentInfo().getOperatorName();
134
+ this.portalOperatorInitials$ = this.utils.getInitials(this.portalOperator$ ?? '');
135
+ this.showAppName$ = this.configProps$.showAppName;
136
+
137
+ this.portalApp$ = PCore.getEnvironmentInfo().getApplicationLabel();
138
+ this.chRef.markForCheck();
141
139
  }
142
140
 
143
141
  navPanelButtonClick(oPageData: any) {
@@ -1,4 +1,4 @@
1
- import { Component, OnInit, Input, NgZone, forwardRef, OnDestroy, inject } from '@angular/core';
1
+ import { ChangeDetectorRef, Component, OnInit, Input, forwardRef, OnDestroy, inject } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
4
4
  import { interval, Subscription } from 'rxjs';
@@ -56,7 +56,7 @@ export class RootContainerComponent implements OnInit, OnDestroy {
56
56
  constructor(
57
57
  private angularPConnect: AngularPConnectService,
58
58
  private psService: ProgressSpinnerService,
59
- private ngZone: NgZone
59
+ private cdRef: ChangeDetectorRef
60
60
  ) {}
61
61
 
62
62
  ngOnInit(): void {
@@ -137,18 +137,16 @@ export class RootContainerComponent implements OnInit, OnDestroy {
137
137
  });
138
138
 
139
139
  setTimeout(() => {
140
- // makes sure Angular tracks these changes
141
- this.ngZone.run(() => {
142
- const theNewPConn = rootObject.getPConnect();
143
- // update ComponentName$ before we update pConn$ to make sure they're in sync
144
- // when rendering...
145
- this.componentName$ = theNewPConn.getComponentName();
146
-
147
- this.pConn$ = theNewPConn;
148
- // this.pConn$ = rootObject.getPConnect();
149
-
150
- console.log(`RootContainer updated pConn$ to be: ${this.componentName$}`);
151
- });
140
+ const theNewPConn = rootObject.getPConnect();
141
+ // update ComponentName$ before we update pConn$ to make sure they're in sync
142
+ // when rendering...
143
+ this.componentName$ = theNewPConn.getComponentName();
144
+
145
+ this.pConn$ = theNewPConn;
146
+ // this.pConn$ = rootObject.getPConnect();
147
+
148
+ console.log(`RootContainer updated pConn$ to be: ${this.componentName$}`);
149
+ this.cdRef.markForCheck();
152
150
  });
153
151
  }
154
152
  }
@@ -187,24 +185,23 @@ export class RootContainerComponent implements OnInit, OnDestroy {
187
185
  if (arChildren && arChildren.length == 1) {
188
186
  // have to have a quick timeout or get an "expressions changed" angular error
189
187
  setTimeout(() => {
190
- this.ngZone.run(() => {
191
- const localPConn = arChildren[0].getPConnect();
192
-
193
- this.componentName$ = localPConn.getComponentName();
194
- if (this.componentName$ === 'ViewContainer') {
195
- const configProps = this.pConn$.getConfigProps();
196
- const viewContConfig = {
197
- meta: {
198
- type: 'ViewContainer',
199
- config: configProps
200
- },
201
- options
202
- };
203
-
204
- this.viewContainerPConn$ = PCore.createPConnect(viewContConfig).getPConnect();
205
- }
206
- this.bShowRoot$ = true;
207
- });
188
+ const localPConn = arChildren[0].getPConnect();
189
+
190
+ this.componentName$ = localPConn.getComponentName();
191
+ if (this.componentName$ === 'ViewContainer') {
192
+ const configProps = this.pConn$.getConfigProps();
193
+ const viewContConfig = {
194
+ meta: {
195
+ type: 'ViewContainer',
196
+ config: configProps
197
+ },
198
+ options
199
+ };
200
+
201
+ this.viewContainerPConn$ = PCore.createPConnect(viewContConfig).getPConnect();
202
+ }
203
+ this.bShowRoot$ = true;
204
+ this.cdRef.markForCheck();
208
205
  });
209
206
  }
210
207
  }
@@ -222,9 +219,8 @@ export class RootContainerComponent implements OnInit, OnDestroy {
222
219
  console.log(ex);
223
220
  }
224
221
 
225
- this.ngZone.run(() => {
226
- this.bIsProgress$ = true;
227
- });
222
+ this.bIsProgress$ = true;
223
+ this.cdRef.markForCheck();
228
224
  });
229
225
  }
230
226
  }
@@ -236,9 +232,8 @@ export class RootContainerComponent implements OnInit, OnDestroy {
236
232
  // don't touch bIsProgress$ unless differnent
237
233
  if (bShow != this.bIsProgress$) {
238
234
  // makes sure Angular tracks these changes
239
- this.ngZone.run(() => {
240
- this.bIsProgress$ = bShow;
241
- });
235
+ this.bIsProgress$ = bShow;
236
+ this.cdRef.markForCheck();
242
237
  }
243
238
  }
244
239
  }
@@ -1,4 +1,4 @@
1
- import { Component, OnInit, Input, NgZone, forwardRef, OnDestroy } from '@angular/core';
1
+ import { ChangeDetectorRef, Component, OnInit, Input, forwardRef, OnDestroy } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { MatSnackBarModule, MatSnackBar } from '@angular/material/snack-bar';
4
4
  import { Subscription } from 'rxjs';
@@ -59,7 +59,7 @@ export class AppShellComponent implements OnInit, OnDestroy {
59
59
  private angularPConnect: AngularPConnectService,
60
60
  private erService: ErrorMessagesService,
61
61
  private snackBar: MatSnackBar,
62
- private ngZone: NgZone,
62
+ private cdRef: ChangeDetectorRef,
63
63
  private utils: Utils
64
64
  ) {}
65
65
 
@@ -152,17 +152,15 @@ export class AppShellComponent implements OnInit, OnDestroy {
152
152
  const portalClass = this.pConn$.getValue('.classID', ''); // 2nd arg empty string until typedef marked correctly
153
153
  const envPortalName = envInfo.getPortalName();
154
154
 
155
- this.ngZone.run(() => {
156
- // making a copy, so can add info
157
- this.pages$ = this.configProps$.pages;
155
+ // making a copy, so can add info
156
+ this.pages$ = this.configProps$.pages;
158
157
 
159
- if (this.pages$) {
160
- this.bShowAppShell$ = true;
161
- }
158
+ if (this.pages$) {
159
+ this.bShowAppShell$ = true;
160
+ }
162
161
 
163
- this.caseTypes$ = this.configProps$.caseTypes;
164
- this.arChildren$ = this.pConn$.getChildren();
165
- });
162
+ this.caseTypes$ = this.configProps$.caseTypes;
163
+ this.arChildren$ = this.pConn$.getChildren();
166
164
 
167
165
  const portalLogo = this.configProps$.portalLogo;
168
166
  // using the default icon then fetch it from the static folder (not auth involved)
@@ -181,12 +179,14 @@ export class AppShellComponent implements OnInit, OnDestroy {
181
179
  .getSvcImageUrl(portalLogo)
182
180
  .then(data => {
183
181
  this.imageURL = data;
182
+ this.cdRef.markForCheck();
184
183
  })
185
184
  .catch(() => {
186
185
  console.error(`${this.localizedVal('Unable to load the image for the portal logo/icon with the insName', 'AppShell')}:${portalLogo}`);
187
186
  });
188
187
  }
189
188
  this.appName$ = this.localizedVal(appNameToDisplay || '', '', `${portalClass}!PORTAL!${envPortalName}`.toUpperCase());
189
+ this.cdRef.markForCheck();
190
190
  }
191
191
 
192
192
  // fpr show/hiding error messages in the SnackBar component
@@ -244,5 +244,6 @@ export class AppShellComponent implements OnInit, OnDestroy {
244
244
  default:
245
245
  break;
246
246
  }
247
+ this.cdRef.markForCheck();
247
248
  }
248
249
  }
@@ -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 {
@@ -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
  }
@@ -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: '',
@@ -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>
@@ -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',
@@ -168,6 +175,12 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
168
175
  targetClassLabel: string;
169
176
  localizedVal = PCore.getLocaleUtils().getLocaleValue;
170
177
  localeCategory = 'SimpleTable';
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,13 +409,19 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
391
409
  }
392
410
 
393
411
  initializeDefaultPageInstructions() {
412
+ if (!this.isInitialized) {
413
+ return;
414
+ }
415
+
416
+ this.isInitialized = false;
417
+
394
418
  if (this.allowEditingInModal) {
395
419
  this.pConn$.getListActions().initDefaultPageInstructions(
396
420
  this.pConn$.getReferenceList(),
397
- this.fieldDefs.filter(item => item.name).map(item => item.name)
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)
398
423
  );
399
- } else if (this.isInitialized) {
400
- this.isInitialized = false;
424
+ } else {
401
425
  // @ts-ignore - An argument for 'propertyNames' was not provided.
402
426
  this.pConn$.getListActions().initDefaultPageInstructions(this.pConn$.getReferenceList());
403
427
  }
@@ -408,6 +432,31 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
408
432
  return `${recordsCount || 0} result${recordsCount > 1 ? 's' : ''}`;
409
433
  }
410
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
+
411
460
  sortCompare(a, b): number {
412
461
  let aValue = a[0][this.compareRef];
413
462
  let bValue = b[0][this.compareRef];
@@ -927,9 +976,13 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
927
976
  // See what data (if any) we have to display
928
977
  const refKeys: string[] = inColKey.split('.');
929
978
  let valBuilder = inRowData;
979
+ let index = 0;
980
+
930
981
  for (const key of refKeys) {
931
- valBuilder = valBuilder[key] ? valBuilder[key] : valBuilder;
982
+ index += 1;
983
+ valBuilder = valBuilder[key] !== undefined || index === refKeys.length ? valBuilder[key] : valBuilder;
932
984
  }
985
+
933
986
  return valBuilder;
934
987
  }
935
988
 
@@ -986,7 +1039,7 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
986
1039
  }
987
1040
 
988
1041
  editRecord(data, index) {
989
- if (data) {
1042
+ if (data && Number.isInteger(index) && index >= 0 && index < this.referenceList.length) {
990
1043
  const viewForEdit = this.bUseSeparateViewForEdit ? this.editView : this.defaultView;
991
1044
  this.pConn$
992
1045
  .getActionsApi()
@@ -1004,14 +1057,19 @@ export class SimpleTableManualComponent implements OnInit, OnDestroy {
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;