@pega/angular-sdk-overrides 0.24.8 → 0.25.1

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 (172) hide show
  1. package/lib/designSystemExtension/alert/alert.component.ts +0 -1
  2. package/lib/designSystemExtension/alert-banner/alert-banner.component.ts +1 -2
  3. package/lib/designSystemExtension/banner/banner.component.ts +0 -1
  4. package/lib/designSystemExtension/case-create-stage/case-create-stage.component.ts +1 -2
  5. package/lib/designSystemExtension/field-group/field-group.component.ts +0 -1
  6. package/lib/designSystemExtension/material-case-summary/material-case-summary.component.scss +2 -1
  7. package/lib/designSystemExtension/material-case-summary/material-case-summary.component.ts +0 -2
  8. package/lib/designSystemExtension/material-details/material-details.component.ts +0 -1
  9. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.html +2 -2
  10. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.ts +10 -2
  11. package/lib/designSystemExtension/material-summary-item/material-summary-item.component.ts +0 -1
  12. package/lib/designSystemExtension/material-summary-list/material-summary-list.component.ts +0 -1
  13. package/lib/designSystemExtension/material-vertical-tabs/material-vertical-tabs.component.ts +0 -1
  14. package/lib/designSystemExtension/operator/operator.component.html +1 -1
  15. package/lib/designSystemExtension/operator/operator.component.scss +10 -2
  16. package/lib/designSystemExtension/operator/operator.component.ts +5 -5
  17. package/lib/designSystemExtension/pulse/pulse.component.ts +7 -8
  18. package/lib/designSystemExtension/rich-text-editor/rich-text-editor.component.ts +0 -1
  19. package/lib/designSystemExtension/wss-quick-create/wss-quick-create.component.ts +0 -1
  20. package/lib/field/auto-complete/auto-complete.component.html +0 -1
  21. package/lib/field/auto-complete/auto-complete.component.ts +31 -16
  22. package/lib/field/cancel-alert/cancel-alert.component.ts +0 -1
  23. package/lib/field/check-box/check-box.component.html +18 -6
  24. package/lib/field/check-box/check-box.component.ts +17 -12
  25. package/lib/field/currency/currency.component.html +4 -4
  26. package/lib/field/currency/currency.component.ts +42 -20
  27. package/lib/field/date/date.component.html +3 -7
  28. package/lib/field/date/date.component.ts +22 -40
  29. package/lib/field/date-time/date-time.component.html +3 -4
  30. package/lib/field/date-time/date-time.component.ts +35 -17
  31. package/lib/field/decimal/decimal.component.html +4 -3
  32. package/lib/field/decimal/decimal.component.ts +47 -22
  33. package/lib/field/dropdown/dropdown.component.html +1 -0
  34. package/lib/field/dropdown/dropdown.component.ts +146 -19
  35. package/lib/field/email/email.component.ts +24 -5
  36. package/lib/field/group/group.component.ts +2 -3
  37. package/lib/field/integer/integer.component.ts +22 -5
  38. package/lib/field/list-view-action-buttons/list-view-action-buttons.component.html +1 -1
  39. package/lib/field/list-view-action-buttons/list-view-action-buttons.component.ts +3 -3
  40. package/lib/field/location/config-ext.json +8 -0
  41. package/lib/field/location/location.component.html +45 -0
  42. package/lib/field/location/location.component.scss +18 -0
  43. package/lib/field/location/location.component.spec.ts +22 -0
  44. package/lib/field/location/location.component.ts +385 -0
  45. package/lib/field/multiselect/multiselect.component.ts +17 -10
  46. package/lib/field/percentage/percentage.component.html +3 -3
  47. package/lib/field/percentage/percentage.component.ts +45 -21
  48. package/lib/field/phone/config-ext.json +1 -1
  49. package/lib/field/phone/phone.component.html +9 -6
  50. package/lib/field/phone/phone.component.scss +9 -0
  51. package/lib/field/phone/phone.component.ts +30 -27
  52. package/lib/field/radio-buttons/radio-buttons.component.html +17 -12
  53. package/lib/field/radio-buttons/radio-buttons.component.ts +13 -10
  54. package/lib/field/rich-text/rich-text.component.ts +19 -9
  55. package/lib/field/scalar-list/scalar-list.component.ts +3 -5
  56. package/lib/field/selectable-card/selectable-card.component.html +40 -0
  57. package/lib/field/selectable-card/selectable-card.component.scss +0 -0
  58. package/lib/field/selectable-card/selectable-card.component.spec.ts +22 -0
  59. package/lib/field/selectable-card/selectable-card.component.ts +255 -0
  60. package/lib/field/semantic-link/semantic-link.component.ts +0 -1
  61. package/lib/field/text/text.component.ts +8 -5
  62. package/lib/field/text-area/text-area.component.html +4 -1
  63. package/lib/field/text-area/text-area.component.ts +22 -6
  64. package/lib/field/text-content/text-content.component.ts +0 -1
  65. package/lib/field/text-input/text-input.component.ts +22 -5
  66. package/lib/field/time/time.component.html +2 -2
  67. package/lib/field/time/time.component.ts +35 -7
  68. package/lib/field/url/url.component.ts +22 -5
  69. package/lib/field/user-reference/user-reference.component.html +40 -46
  70. package/lib/field/user-reference/user-reference.component.ts +111 -21
  71. package/lib/infra/Containers/flow-container/flow-container.component.html +1 -1
  72. package/lib/infra/Containers/flow-container/flow-container.component.ts +25 -48
  73. package/lib/infra/Containers/flow-container/helpers.ts +2 -2
  74. package/lib/infra/Containers/hybrid-view-container/hybrid-view-container.component.ts +0 -1
  75. package/lib/infra/Containers/modal-view-container/modal-view-container.component.html +1 -11
  76. package/lib/infra/Containers/modal-view-container/modal-view-container.component.ts +1 -9
  77. package/lib/infra/Containers/preview-view-container/preview-view-container.component.ts +1 -1
  78. package/lib/infra/Containers/view-container/helper.ts +22 -0
  79. package/lib/infra/Containers/view-container/view-container.component.ts +5 -18
  80. package/lib/infra/action-buttons/action-buttons.component.html +1 -1
  81. package/lib/infra/action-buttons/action-buttons.component.ts +0 -1
  82. package/lib/infra/assignment/assignment.component.html +1 -1
  83. package/lib/infra/assignment/assignment.component.ts +82 -41
  84. package/lib/infra/assignment-card/assignment-card.component.html +1 -0
  85. package/lib/infra/assignment-card/assignment-card.component.ts +0 -1
  86. package/lib/infra/dashboard-filter/dashboard-filter.component.ts +0 -1
  87. package/lib/infra/defer-load/defer-load.component.ts +8 -6
  88. package/lib/infra/error-boundary/error-boundary.component.ts +0 -1
  89. package/lib/infra/multi-step/multi-step.component.ts +0 -1
  90. package/lib/infra/navbar/navbar.component.ts +3 -6
  91. package/lib/infra/reference/reference.component.ts +77 -90
  92. package/lib/infra/region/region.component.ts +0 -1
  93. package/lib/infra/root-container/root-container.component.html +2 -15
  94. package/lib/infra/root-container/root-container.component.ts +27 -33
  95. package/lib/infra/stages/stages.component.scss +2 -2
  96. package/lib/infra/stages/stages.component.ts +0 -1
  97. package/lib/infra/view/view.component.html +7 -20
  98. package/lib/infra/view/view.component.ts +20 -3
  99. package/lib/template/app-shell/app-shell.component.ts +20 -3
  100. package/lib/template/banner-page/banner-page.component.ts +0 -1
  101. package/lib/template/base/details-template-base.ts +67 -0
  102. package/lib/template/base/form-template-base.ts +16 -0
  103. package/lib/template/case-summary/case-summary.component.ts +7 -23
  104. package/lib/template/case-view/case-view.component.html +4 -4
  105. package/lib/template/case-view/case-view.component.ts +8 -14
  106. package/lib/template/confirmation/confirmation.component.html +1 -1
  107. package/lib/template/confirmation/confirmation.component.ts +1 -2
  108. package/lib/template/data-reference/data-reference.component.ts +36 -41
  109. package/lib/template/default-form/default-form.component.html +0 -4
  110. package/lib/template/default-form/default-form.component.ts +41 -25
  111. package/lib/template/details/details.component.ts +7 -42
  112. package/lib/template/details-narrow-wide/details-narrow-wide.component.ts +6 -40
  113. package/lib/template/details-one-column/details-one-column.component.ts +7 -43
  114. package/lib/template/details-sub-tabs/details-sub-tabs.component.html +1 -2
  115. package/lib/template/details-sub-tabs/details-sub-tabs.component.ts +5 -38
  116. package/lib/template/details-three-column/details-three-column.component.ts +7 -44
  117. package/lib/template/details-two-column/details-two-column.component.ts +8 -45
  118. package/lib/template/details-wide-narrow/details-wide-narrow.component.ts +7 -43
  119. package/lib/template/dynamic-tabs/dynamic-tabs.component.html +3 -0
  120. package/lib/template/dynamic-tabs/dynamic-tabs.component.ts +8 -4
  121. package/lib/template/field-group-list/field-group-list.component.ts +0 -1
  122. package/lib/template/field-group-template/field-group-template.component.html +7 -7
  123. package/lib/template/field-group-template/field-group-template.component.scss +8 -0
  124. package/lib/template/field-group-template/field-group-template.component.ts +68 -48
  125. package/lib/template/field-value-list/field-value-list.component.html +2 -2
  126. package/lib/template/field-value-list/field-value-list.component.scss +6 -1
  127. package/lib/template/field-value-list/field-value-list.component.ts +0 -1
  128. package/lib/template/inline-dashboard/inline-dashboard.component.ts +0 -1
  129. package/lib/template/inline-dashboard-page/inline-dashboard-page.component.ts +2 -3
  130. package/lib/template/list-page/list-page.component.ts +0 -1
  131. package/lib/template/list-view/list-view.component.html +6 -1
  132. package/lib/template/list-view/list-view.component.scss +11 -0
  133. package/lib/template/list-view/list-view.component.ts +25 -11
  134. package/lib/template/list-view/listViewHelpers.ts +4 -10
  135. package/lib/template/list-view/utils.ts +2 -5
  136. package/lib/template/multi-reference-readonly/multi-reference-readonly.component.ts +0 -1
  137. package/lib/template/narrow-wide-form/narrow-wide-form.component.ts +1 -2
  138. package/lib/template/one-column/one-column.component.ts +4 -4
  139. package/lib/template/one-column-page/one-column-page.component.ts +0 -1
  140. package/lib/template/one-column-tab/one-column-tab.component.ts +1 -2
  141. package/lib/template/page/page.component.ts +1 -2
  142. package/lib/template/promoted-filters/promoted-filters.component.ts +1 -2
  143. package/lib/template/repeating-structures/repeating-structures.component.ts +1 -2
  144. package/lib/template/simple-table/simple-table.component.ts +0 -1
  145. package/lib/template/simple-table-manual/helpers.ts +126 -10
  146. package/lib/template/simple-table-manual/simple-table-manual.component.html +25 -6
  147. package/lib/template/simple-table-manual/simple-table-manual.component.scss +12 -3
  148. package/lib/template/simple-table-manual/simple-table-manual.component.ts +110 -54
  149. package/lib/template/simple-table-select/simple-table-select.component.ts +3 -4
  150. package/lib/template/single-reference-readonly/single-reference-readonly.component.ts +0 -1
  151. package/lib/template/sub-tabs/sub-tabs.component.ts +0 -1
  152. package/lib/template/three-column/three-column.component.ts +4 -4
  153. package/lib/template/three-column-page/three-column-page.component.ts +0 -1
  154. package/lib/template/two-column/two-column.component.ts +4 -4
  155. package/lib/template/two-column-page/two-column-page.component.ts +0 -1
  156. package/lib/template/two-column-tab/two-column-tab.component.ts +1 -2
  157. package/lib/template/utils.ts +16 -0
  158. package/lib/template/wide-narrow-form/wide-narrow-form.component.ts +4 -4
  159. package/lib/template/wide-narrow-page/wide-narrow-page.component.ts +1 -2
  160. package/lib/template/wss-nav-bar/wss-nav-bar.component.ts +3 -4
  161. package/lib/widget/app-announcement/app-announcement.component.ts +0 -1
  162. package/lib/widget/attachment/attachment.component.ts +9 -13
  163. package/lib/widget/case-history/case-history.component.ts +0 -1
  164. package/lib/widget/feed-container/feed-container.component.ts +7 -10
  165. package/lib/widget/file-utility/file-utility.component.ts +2 -6
  166. package/lib/widget/list-utility/list-utility.component.ts +0 -1
  167. package/lib/widget/quick-create/quick-create.component.ts +0 -1
  168. package/lib/widget/todo/todo.component.html +5 -6
  169. package/lib/widget/todo/todo.component.scss +9 -0
  170. package/lib/widget/todo/todo.component.ts +95 -85
  171. package/lib/widget/utility/utility.component.ts +0 -1
  172. package/package.json +1 -1
@@ -3,7 +3,8 @@ import { CommonModule } from '@angular/common';
3
3
  import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
4
4
  import { MatFormFieldModule } from '@angular/material/form-field';
5
5
  import { interval } from 'rxjs';
6
- import { NgxMatIntlTelInputComponent } from 'ngx-mat-intl-tel-input';
6
+ import { MatTelInput } from 'mat-tel-input';
7
+ import { parsePhoneNumberFromString } from 'libphonenumber-js';
7
8
  import { Utils } from '@pega/angular-sdk-components';
8
9
  import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
9
10
  import { handleEvent } from '@pega/angular-sdk-components';
@@ -18,8 +19,7 @@ interface PhoneProps extends PConnFieldProps {
18
19
  selector: 'app-phone',
19
20
  templateUrl: './phone.component.html',
20
21
  styleUrls: ['./phone.component.scss'],
21
- standalone: true,
22
- imports: [CommonModule, ReactiveFormsModule, MatFormFieldModule, NgxMatIntlTelInputComponent, forwardRef(() => ComponentMapperComponent)]
22
+ imports: [CommonModule, ReactiveFormsModule, MatFormFieldModule, MatTelInput, forwardRef(() => ComponentMapperComponent)]
23
23
  })
24
24
  export class PhoneComponent implements OnInit, OnDestroy {
25
25
  @Input() pConn$: typeof PConnect;
@@ -38,17 +38,15 @@ export class PhoneComponent implements OnInit, OnDestroy {
38
38
  displayMode$?: string = '';
39
39
  controlName$: string;
40
40
  bHasForm$ = true;
41
- componentReference = '';
42
41
  testId: string;
43
- separateDialCode = false;
44
- afterBlur: boolean;
45
42
  helperText: string;
43
+ placeholder: string;
46
44
 
47
45
  fieldControl = new FormControl('', null);
48
46
 
49
- phoneForm = new FormGroup({
50
- phone: new FormControl<string | null>(null)
51
- });
47
+ actionsApi: Object;
48
+ propName: string;
49
+ preferredCountries: string[] = ['us'];
52
50
 
53
51
  constructor(
54
52
  private angularPConnect: AngularPConnectService,
@@ -114,8 +112,13 @@ export class PhoneComponent implements OnInit, OnDestroy {
114
112
  this.testId = this.configProps$.testId;
115
113
  if (this.configProps$.value != undefined) {
116
114
  this.value$ = this.configProps$.value;
115
+ this.fieldControl.setValue(this.value$);
116
+ this.updatePreferredCountries();
117
117
  }
118
118
  this.helperText = this.configProps$.helperText;
119
+ this.placeholder = this.configProps$.placeholder || '';
120
+ this.actionsApi = this.pConn$.getActionsApi();
121
+ this.propName = this.pConn$.getStateProps().value;
119
122
 
120
123
  // timeout and detectChanges to avoid ExpressionChangedAfterItHasBeenCheckedError
121
124
  setTimeout(() => {
@@ -144,10 +147,6 @@ export class PhoneComponent implements OnInit, OnDestroy {
144
147
  this.bReadonly$ = this.utils.getBooleanValue(this.configProps$.readOnly);
145
148
  }
146
149
 
147
- if (this.bReadonly$) {
148
- this.phoneForm.setValue({ phone: this.value$ });
149
- }
150
-
151
150
  // trigger display of error message with field control
152
151
  if (this.angularPConnectData.validateMessage != null && this.angularPConnectData.validateMessage != '') {
153
152
  const timer = interval(100).subscribe(() => {
@@ -159,25 +158,29 @@ export class PhoneComponent implements OnInit, OnDestroy {
159
158
  }
160
159
  }
161
160
 
161
+ fieldOnBlur() {
162
+ // 'blur' isn't getting fired
163
+ }
164
+
162
165
  fieldOnChange() {
163
- if (this.formGroup$.controls[this.controlName$].value) {
164
- const actionsApi = this.pConn$?.getActionsApi();
165
- const propName = (this.pConn$?.getStateProps() as any).value;
166
+ const oldVal = this.value$ ?? '';
167
+ const newVal = this.formGroup$.controls[this.controlName$].value;
168
+ const isValueChanged = newVal?.toString() !== oldVal.toString();
169
+
170
+ if (isValueChanged && newVal) {
166
171
  const value = this.formGroup$.controls[this.controlName$].value;
167
- const eventObj = {
168
- target: {
169
- value
170
- }
171
- };
172
- this.afterBlur = true;
173
- this.angularPConnectData.actions?.onChange(this, eventObj);
174
- handleEvent(actionsApi, 'blur', propName, value);
172
+ handleEvent(this.actionsApi, 'changeNblur', this.propName, value);
175
173
  }
176
174
  }
177
175
 
178
- fieldOnBlur(event: any) {
179
- // PConnect wants to use eventHandler for onBlur
180
- this.angularPConnectData.actions?.onBlur(this, event);
176
+ updatePreferredCountries() {
177
+ if (this.value$ && typeof this.value$ === 'string') {
178
+ const phoneNumber = parsePhoneNumberFromString(this.value$);
179
+ this.preferredCountries =
180
+ phoneNumber?.country && !this.preferredCountries.includes(phoneNumber?.country.toLowerCase())
181
+ ? [phoneNumber?.country?.toLowerCase(), ...this.preferredCountries]
182
+ : this.preferredCountries;
183
+ }
181
184
  }
182
185
 
183
186
  getErrorMessage() {
@@ -1,18 +1,17 @@
1
- <div *ngIf="displayMode$; else noDisplayMode">
2
- <component-mapper
3
- *ngIf="bVisible$ !== false"
4
- name="FieldValueList"
5
- [props]="{ label$, value$: this.localizedValue, displayMode$ }"
6
- ></component-mapper>
1
+ <div *ngIf="variant !== 'card'; else cardMode">
2
+ <div *ngIf="displayMode$; else noDisplayMode">
3
+ <component-mapper
4
+ *ngIf="bVisible$ !== false"
5
+ name="FieldValueList"
6
+ [props]="{ label$, value$: this.localizedValue, displayMode$ }"
7
+ ></component-mapper>
8
+ </div>
7
9
  </div>
8
10
  <ng-template #noDisplayMode>
9
11
  <div [formGroup]="formGroup$" *ngIf="bVisible$">
10
12
  <mat-form-field class="psdk-radio-form" subscriptSizing="dynamic" [hintLabel]="helperText">
11
- <span class="psdk-label-wrapper-readonly">
12
- <label class="psdk-label-readonly">{{ label$ }}</label>
13
- </span>
14
- <!-- <mat-label>{{label$}}</mat-label> -->
15
- <input matInput [placeholder]="placeholder" style="display: none" />
13
+ <mat-label>{{ label$ }}</mat-label>
14
+ <input matInput [placeholder]="placeholder" style="display: none" [required]="bRequired$" />
16
15
  <mat-radio-group
17
16
  [value]="value$"
18
17
  [required]="bRequired$"
@@ -24,7 +23,7 @@
24
23
  <mat-radio-button
25
24
  *ngFor="let opt of options$"
26
25
  [checked]="isSelected(opt.key)"
27
- [disabled]="bReadonly$"
26
+ [disabled]="bDisabled$ || bReadonly$"
28
27
  [value]="opt.key"
29
28
  class="psdk-radio-button"
30
29
  >
@@ -35,3 +34,9 @@
35
34
  </mat-form-field>
36
35
  </div>
37
36
  </ng-template>
37
+ <ng-template #cardMode>
38
+ <h4>{{ label$ }}</h4>
39
+ <div>
40
+ <component-mapper name="SelectableCard" [props]="{ pConn$: pConn$, type: 'radio' }" [parent]="this"></component-mapper>
41
+ </div>
42
+ </ng-template>
@@ -9,6 +9,7 @@ import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-c
9
9
  import { Utils } from '@pega/angular-sdk-components';
10
10
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
11
11
  import { PConnFieldProps } from '@pega/angular-sdk-components';
12
+ import { handleEvent } from '@pega/angular-sdk-components';
12
13
 
13
14
  interface IOption {
14
15
  key: string;
@@ -19,6 +20,7 @@ interface RadioButtonsProps extends PConnFieldProps {
19
20
  // If any, enter additional props that only exist on RadioButtons here
20
21
  inline: boolean;
21
22
  fieldMetadata?: any;
23
+ variant?: string;
22
24
  }
23
25
 
24
26
  @Component({
@@ -26,7 +28,6 @@ interface RadioButtonsProps extends PConnFieldProps {
26
28
  templateUrl: './radio-buttons.component.html',
27
29
  styleUrls: ['./radio-buttons.component.scss'],
28
30
  providers: [Utils],
29
- standalone: true,
30
31
  imports: [CommonModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatRadioModule, forwardRef(() => ComponentMapperComponent)]
31
32
  })
32
33
  export class RadioButtonsComponent implements OnInit, OnDestroy {
@@ -60,6 +61,9 @@ export class RadioButtonsComponent implements OnInit, OnDestroy {
60
61
  localeName = '';
61
62
  localePath = '';
62
63
  localizedValue = '';
64
+ actionsApi: Object;
65
+ propName: string;
66
+ variant?: string;
63
67
 
64
68
  constructor(
65
69
  private angularPConnect: AngularPConnectService,
@@ -130,6 +134,8 @@ export class RadioButtonsComponent implements OnInit, OnDestroy {
130
134
  this.helperText = this.configProps$.helperText;
131
135
  this.placeholder = this.configProps$.placeholder || '';
132
136
 
137
+ this.variant = this.configProps$.variant;
138
+
133
139
  // timeout and detectChanges to avoid ExpressionChangedAfterItHasBeenCheckedError
134
140
  setTimeout(() => {
135
141
  if (this.configProps$.required != null) {
@@ -164,13 +170,15 @@ export class RadioButtonsComponent implements OnInit, OnDestroy {
164
170
  this.bReadonly$ = this.utils.getBooleanValue(this.configProps$.readOnly);
165
171
  }
166
172
 
167
- this.componentReference = (this.pConn$.getStateProps() as any).value;
173
+ this.componentReference = this.pConn$.getStateProps().value;
168
174
 
169
175
  this.options$ = this.utils.getOptionList(this.configProps$, this.pConn$.getDataObject());
170
176
 
171
- const propName = (this.pConn$.getStateProps() as any).value;
177
+ this.actionsApi = this.pConn$.getActionsApi();
178
+ this.propName = this.pConn$.getStateProps().value;
179
+
172
180
  const className = this.pConn$.getCaseInfo().getClassName();
173
- const refName = propName?.slice(propName.lastIndexOf('.') + 1);
181
+ const refName = this.propName?.slice(this.propName.lastIndexOf('.') + 1);
174
182
 
175
183
  this.fieldMetadata = this.configProps$.fieldMetadata;
176
184
  const metaData = Array.isArray(this.fieldMetadata) ? this.fieldMetadata.filter(field => field?.classID === className)[0] : this.fieldMetadata;
@@ -203,12 +211,7 @@ export class RadioButtonsComponent implements OnInit, OnDestroy {
203
211
  }
204
212
 
205
213
  fieldOnChange(event: any) {
206
- this.angularPConnectData.actions?.onChange(this, event);
207
- }
208
-
209
- fieldOnBlur(event: any) {
210
- // PConnect wants to use eventHandler for onBlur
211
- this.angularPConnectData.actions?.onBlur(this, event);
214
+ handleEvent(this.actionsApi, 'changeNblur', this.propName, event.value);
212
215
  }
213
216
 
214
217
  getLocalizedOptionValue(opt: IOption) {
@@ -15,7 +15,6 @@ interface RichTextProps extends PConnFieldProps {
15
15
  selector: 'app-rich-text',
16
16
  templateUrl: './rich-text.component.html',
17
17
  styleUrls: ['./rich-text.component.scss'],
18
- standalone: true,
19
18
  imports: [CommonModule, ReactiveFormsModule, forwardRef(() => ComponentMapperComponent)]
20
19
  })
21
20
  export class RichTextComponent implements OnInit, OnDestroy {
@@ -40,6 +39,8 @@ export class RichTextComponent implements OnInit, OnDestroy {
40
39
  info: any;
41
40
  error: boolean;
42
41
  status: any;
42
+ actionsApi: Object;
43
+ propName: string;
43
44
 
44
45
  constructor(
45
46
  private angularPConnect: AngularPConnectService,
@@ -80,7 +81,7 @@ export class RichTextComponent implements OnInit, OnDestroy {
80
81
  updateSelf(): void {
81
82
  // moved this from ngOnInit() and call this from there instead...
82
83
  this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as RichTextProps;
83
- const stateProps: any = this.pConn$.getStateProps();
84
+ const stateProps = this.pConn$.getStateProps();
84
85
  this.status = stateProps?.status;
85
86
 
86
87
  if (this.configProps$.value != undefined) {
@@ -94,6 +95,9 @@ export class RichTextComponent implements OnInit, OnDestroy {
94
95
  this.info = stateProps?.validatemessage || this.configProps$.helperText;
95
96
  this.error = stateProps?.status === 'error';
96
97
 
98
+ this.actionsApi = this.pConn$.getActionsApi();
99
+ this.propName = this.pConn$.getStateProps().value;
100
+
97
101
  if (this.configProps$.required != null) {
98
102
  this.bRequired$ = this.utils.getBooleanValue(this.configProps$.required);
99
103
  }
@@ -111,9 +115,13 @@ export class RichTextComponent implements OnInit, OnDestroy {
111
115
  }
112
116
  }
113
117
 
114
- fieldOnChange() {
115
- if (this.status === 'error') {
116
- const property = (this.pConn$.getStateProps() as any).value;
118
+ fieldOnChange(editorValue: any) {
119
+ const oldVal = this.value$ ?? '';
120
+ const newVal = editorValue?.editor?.getBody()?.innerHTML ?? '';
121
+ const isValueChanged = newVal.toString() !== oldVal.toString();
122
+
123
+ if (isValueChanged || this.status === 'error') {
124
+ const property = this.propName;
117
125
  this.pConn$.clearErrorMessages({
118
126
  property,
119
127
  category: '',
@@ -123,9 +131,11 @@ export class RichTextComponent implements OnInit, OnDestroy {
123
131
  }
124
132
 
125
133
  fieldOnBlur(editorValue: any) {
126
- // PConnect wants to use eventHandler for onBlur
127
- const actionsApi = this.pConn$?.getActionsApi();
128
- const propName = (this.pConn$?.getStateProps() as any).value;
129
- handleEvent(actionsApi, 'changeNblur', propName, editorValue);
134
+ const oldVal = this.value$ ?? '';
135
+ const isValueChanged = editorValue.toString() !== oldVal.toString();
136
+
137
+ if (isValueChanged) {
138
+ handleEvent(this.actionsApi, 'changeNblur', this.propName, editorValue);
139
+ }
130
140
  }
131
141
  }
@@ -17,7 +17,6 @@ interface ScalarListProps extends Omit<PConnFieldProps, 'value'> {
17
17
  selector: 'app-scalar-list',
18
18
  templateUrl: './scalar-list.component.html',
19
19
  styleUrls: ['./scalar-list.component.scss'],
20
- standalone: true,
21
20
  imports: [CommonModule, forwardRef(() => ComponentMapperComponent)]
22
21
  })
23
22
  export class ScalarListComponent implements OnInit, OnDestroy {
@@ -101,20 +100,19 @@ export class ScalarListComponent implements OnInit, OnDestroy {
101
100
  {
102
101
  type: componentType,
103
102
  config: {
104
- // @ts-ignore - Object literal may only specify known properties, and 'value' does not exist in type 'ComponentMetadataConfig'.
105
103
  value: scalarValue,
106
- displayMode: 'LABELS_LEFT',
104
+ displayMode: 'DISPLAY_ONLY',
107
105
  label: this.label$,
108
106
  ...restProps,
109
107
  readOnly: true
110
108
  }
111
109
  },
112
110
  '',
113
- '',
111
+ 0,
114
112
  {}
115
113
  ); // 2nd, 3rd, and 4th args empty string/object/null until typedef marked correctly as optional;
116
114
  });
117
- this.isDisplayModeEnabled = ['LABELS_LEFT', 'STACKED_LARGE_VAL', 'DISPLAY_ONLY'].includes(this.displayMode$ as string);
115
+ this.isDisplayModeEnabled = ['STACKED_LARGE_VAL', 'DISPLAY_ONLY'].includes(this.displayMode$ as string);
118
116
  this.value$ = this.items;
119
117
  }
120
118
  }
@@ -0,0 +1,40 @@
1
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 40ch), 1fr)); grid-auto-rows: 1fr; gap: 0.5rem">
2
+ <div *ngFor="let cardContent of contentList">
3
+ <mat-card [ngStyle]="cardStyle" appearance="outlined" (click)="cardSelect($event, cardContent.commonCardProps)">
4
+ <img
5
+ *ngIf="cardContent.cardImage"
6
+ mat-card-image
7
+ src="{{ cardContent.cardImage.src }}"
8
+ alt="{{ cardContent.cardImage.alt }}"
9
+ [ngStyle]="cardContent.cardImage.style"
10
+ />
11
+ <mat-card-content>
12
+ <div *ngIf="type === 'radio'">
13
+ <mat-radio-button
14
+ [checked]="radioBtnValue === cardContent?.commonCardProps?.key"
15
+ [disabled]="disabled"
16
+ [value]="cardContent.commonCardProps.key"
17
+ (change)="fieldOnChange(cardContent.commonCardProps.key)"
18
+ >
19
+ {{ cardContent.commonCardProps.label }}
20
+ </mat-radio-button>
21
+ </div>
22
+ <div *ngIf="type === 'checkbox'">
23
+ <mat-checkbox
24
+ [labelPosition]="'after'"
25
+ [checked]="cardContent.commonCardProps.selected"
26
+ [disabled]="disabled || readOnly"
27
+ [attr.data-test-id]="testId + ':' + cardContent.commonCardProps.label"
28
+ (change)="handleChangeMultiMode($event, cardContent.commonCardProps)"
29
+ (blur)="fieldOnBlur()"
30
+ >{{ cardContent.commonCardProps.label }}</mat-checkbox
31
+ >
32
+ </div>
33
+ <div *ngFor="let field of cardContent.commonCardProps.fields" [ngStyle]="field.type !== 'TextArea' ? defaultStyle : specialStyle">
34
+ <div style="color: rgba(0, 0, 0, 0.6)">{{ field.name }}</div>
35
+ <div>{{ field?.value?.getPConnect().getConfigProps().value ?? '--' }}</div>
36
+ </div>
37
+ </mat-card-content>
38
+ </mat-card>
39
+ </div>
40
+ </div>
@@ -0,0 +1,22 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { SelectableCardComponent } from './selectable-card.component';
4
+
5
+ describe('SelectableCardComponent', () => {
6
+ let component: SelectableCardComponent;
7
+ let fixture: ComponentFixture<SelectableCardComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ imports: [SelectableCardComponent]
12
+ }).compileComponents();
13
+
14
+ fixture = TestBed.createComponent(SelectableCardComponent);
15
+ component = fixture.componentInstance;
16
+ fixture.detectChanges();
17
+ });
18
+
19
+ it('should create', () => {
20
+ expect(component).toBeTruthy();
21
+ });
22
+ });
@@ -0,0 +1,255 @@
1
+ import { Component, Input, OnInit, OnDestroy, EventEmitter, Output } from '@angular/core';
2
+ import { MatCardModule } from '@angular/material/card';
3
+ import { MatRadioModule } from '@angular/material/radio';
4
+ import { MatCheckboxModule } from '@angular/material/checkbox';
5
+ import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
6
+ import { PConnFieldProps } from '@pega/angular-sdk-components';
7
+ import { CommonModule } from '@angular/common';
8
+ import { deleteInstruction, insertInstruction } from '@pega/angular-sdk-components';
9
+ import { handleEvent } from '@pega/angular-sdk-components';
10
+ import { Utils } from '@pega/angular-sdk-components';
11
+
12
+ interface SelectableCardProps extends PConnFieldProps {
13
+ selectionList: any;
14
+ readonlyContextList: any;
15
+ image: string;
16
+ primaryField: string;
17
+ selectionKey: string;
18
+ renderMode: string;
19
+ hideFieldLabels?: boolean;
20
+ additionalProps?: any;
21
+ imagePosition?: string;
22
+ imageSize?: string;
23
+ showImageDescription?: boolean;
24
+ datasource?: any;
25
+ }
26
+
27
+ @Component({
28
+ selector: 'lib-selectable-card',
29
+ imports: [MatCardModule, CommonModule, MatRadioModule, MatCheckboxModule],
30
+ templateUrl: './selectable-card.component.html',
31
+ styleUrl: './selectable-card.component.scss'
32
+ })
33
+ export class SelectableCardComponent implements OnInit, OnDestroy {
34
+ @Input() pConn$: typeof PConnect;
35
+ @Input() type: string;
36
+ @Output() valueChange: EventEmitter<any> = new EventEmitter();
37
+
38
+ // Used with AngularPConnect
39
+ angularPConnectData: AngularPConnectData = {};
40
+ configProps$: SelectableCardProps;
41
+ value$: any;
42
+ readOnly = false;
43
+ disabled = false;
44
+ displayMode$: string | undefined;
45
+ radioBtnValue;
46
+ additionalProps;
47
+ testId;
48
+ showNoValue = false;
49
+ selectionKey?: string;
50
+ defaultStyle = {};
51
+ specialStyle = {};
52
+ cardStyle = {};
53
+ selectedvalues: any;
54
+ selectionList: any;
55
+ primaryField: string;
56
+ commonProps: any = {};
57
+ contentList: [
58
+ {
59
+ commonCardProps: { id: string; key: string; fields: any; label: string; selected: boolean };
60
+ cardImage: { src: string; alt: string; style: any };
61
+ }
62
+ ];
63
+
64
+ actionsApi: Object;
65
+ propName: string;
66
+
67
+ constructor(
68
+ private angularPConnect: AngularPConnectService,
69
+ private utils: Utils
70
+ ) {}
71
+
72
+ ngOnInit(): void {
73
+ // First thing in initialization is registering and subscribing to the AngularPConnect service
74
+ this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange);
75
+ // styles used in displaying common field props
76
+ this.defaultStyle = {
77
+ display: 'grid',
78
+ gridTemplateColumns: '1fr 1fr',
79
+ margin: '0.5rem',
80
+ wordBreak: 'break-word',
81
+ fontSize: '0.875rem'
82
+ };
83
+ this.specialStyle = {
84
+ margin: '0.5rem',
85
+ fontSize: '0.875rem'
86
+ };
87
+ this.checkAndUpdate();
88
+ }
89
+
90
+ ngOnDestroy(): void {
91
+ if (this.angularPConnectData.unsubscribeFn) {
92
+ this.angularPConnectData.unsubscribeFn();
93
+ }
94
+ }
95
+
96
+ // Callback passed when subscribing to store change
97
+ onStateChange() {
98
+ this.checkAndUpdate();
99
+ }
100
+
101
+ checkAndUpdate() {
102
+ // Should always check the bridge to see if the component should
103
+ // update itself (re-render)
104
+ const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this);
105
+
106
+ // ONLY call updateSelf when the component should update
107
+ if (bUpdateSelf) {
108
+ this.updateSelf();
109
+ }
110
+ }
111
+
112
+ updateSelf(): void {
113
+ this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as SelectableCardProps;
114
+
115
+ this.actionsApi = this.pConn$.getActionsApi();
116
+ this.propName = this.pConn$.getStateProps().value;
117
+
118
+ const hideFieldLabels = this.configProps$.hideFieldLabels;
119
+ const datasource: any = this.configProps$.datasource;
120
+ const additionalProps: any = this.configProps$.additionalProps;
121
+ const imageSize: string = this.configProps$.imageSize ?? ''; // not using
122
+ const showImageDescription: boolean = this.configProps$.showImageDescription ?? false;
123
+ let recordKey = '';
124
+ let cardLabel = '';
125
+ let image: any;
126
+
127
+ this.disabled = this.configProps$.disabled;
128
+ this.readOnly = this.configProps$.renderMode === 'ReadOnly' || this.displayMode$ === 'DISPLAY_ONLY' || this.configProps$.readOnly;
129
+ const imagePosition = this.configProps$.imagePosition;
130
+
131
+ // dynamic styling based on image position and readOnly option
132
+ let imageWidth = '100%';
133
+ this.cardStyle = { display: 'flex', flexDirection: 'column', height: '100%' };
134
+ if (imagePosition && imagePosition !== 'block-start') {
135
+ imageWidth = '30%';
136
+ if (imagePosition === 'inline-start') {
137
+ this.cardStyle = { display: 'flex', flexDirection: 'row', alignItems: this.readOnly ? 'center' : '' };
138
+ } else if (imagePosition === 'inline-end') {
139
+ this.cardStyle = {
140
+ display: 'flex',
141
+ flexDirection: 'row-reverse',
142
+ justifyContent: this.readOnly ? 'space-between' : '',
143
+ alignItems: this.readOnly ? 'center' : ''
144
+ };
145
+ }
146
+ }
147
+ if (this.type === 'radio') {
148
+ const stateProps = this.pConn$.getStateProps();
149
+ image = {
150
+ imagePosition,
151
+ imageSize,
152
+ showImageDescription,
153
+ imageField: stateProps.image?.split('.').pop(),
154
+ imageDescription: stateProps.imageDescription?.split('.').pop()
155
+ };
156
+
157
+ recordKey = stateProps.value?.split('.').pop() ?? '';
158
+ cardLabel = stateProps.primaryField?.split('.').pop() ?? '';
159
+
160
+ this.value$ = this.configProps$.value;
161
+ this.radioBtnValue = this.value$;
162
+ }
163
+
164
+ if (this.type === 'checkbox') {
165
+ this.testId = this.configProps$.testId;
166
+ this.displayMode$ = this.configProps$.displayMode;
167
+
168
+ this.selectionKey = this.configProps$.selectionKey;
169
+ recordKey = this.selectionKey?.split('.').pop() ?? '';
170
+ cardLabel = this.configProps$.primaryField.split('.').pop() ?? '';
171
+
172
+ image = {
173
+ imagePosition,
174
+ imageSize,
175
+ showImageDescription,
176
+ imageField: this.configProps$.image?.split('.').pop(),
177
+ imageDescription: (this.pConn$?.getRawMetadata()?.config as any).imageDescription?.split('.').pop()
178
+ };
179
+
180
+ this.selectionList = this.configProps$.selectionList;
181
+ this.selectedvalues = this.configProps$.readonlyContextList;
182
+ this.showNoValue = this.readOnly && this.selectedvalues.length === 0; // not used
183
+ this.primaryField = this.configProps$.primaryField;
184
+ }
185
+
186
+ this.commonProps = { hideFieldLabels, datasource, additionalProps, image, recordKey, cardLabel, radioBtnValue: this.radioBtnValue ?? '' };
187
+ const imageDescriptionKey = this.commonProps?.image?.showImageDescription ? this.commonProps?.image?.imageDescription : undefined;
188
+ const cardDataSource = this.readOnly || this.displayMode$ == 'DISPLAY_ONLY' ? this.selectedvalues || [] : this.commonProps?.datasource?.source;
189
+
190
+ this.contentList = cardDataSource.map(item => {
191
+ const resolvedFields = this.utils.resolveReferenceFields(item, this.commonProps.hideFieldLabels, this.commonProps.recordKey, this.pConn$);
192
+ const commonCardProps = {
193
+ id: item[this.commonProps.recordKey],
194
+ key: item[this.commonProps.recordKey],
195
+ fields: resolvedFields,
196
+ label: item[this.commonProps.cardLabel],
197
+ selected: this.selectedvalues
198
+ ? this.selectedvalues?.some?.(data => data[this.commonProps.recordKey] === item[this.commonProps.recordKey])
199
+ : false
200
+ };
201
+ const cardImage = item[this.commonProps.image.imageField]
202
+ ? {
203
+ src: item[this.commonProps.image.imageField],
204
+ alt: this.commonProps.image.showImageDescription && imageDescriptionKey ? item[imageDescriptionKey] : '',
205
+ style: {
206
+ width: imageWidth,
207
+ backgroundColor: 'rgb(233, 238, 243)',
208
+ aspectRatio: '16/9',
209
+ maxHeight: '100%',
210
+ objectFit: 'contain',
211
+ maxWidth: '100%',
212
+ height: this.readOnly && imagePosition !== 'block-start' ? '5rem' : ''
213
+ }
214
+ }
215
+ : undefined;
216
+
217
+ return { cardImage, commonCardProps };
218
+ });
219
+ }
220
+
221
+ fieldOnChange(value: any) {
222
+ handleEvent(this.actionsApi, 'changeNblur', this.propName, value);
223
+ }
224
+
225
+ fieldOnBlur() {
226
+ this.pConn$.getValidationApi().validate(this.selectedvalues, this.selectionList);
227
+ }
228
+
229
+ handleChangeMultiMode(event, element) {
230
+ if (!element.selected) {
231
+ insertInstruction(this.pConn$, this.selectionList, this.selectionKey, this.primaryField, {
232
+ id: element.id,
233
+ primary: element.label
234
+ });
235
+ } else {
236
+ deleteInstruction(this.pConn$, this.selectionList, this.selectionKey, {
237
+ id: element.key,
238
+ primary: element.label
239
+ });
240
+ }
241
+ this.pConn$.clearErrorMessages({
242
+ property: this.selectionList,
243
+ category: '',
244
+ context: ''
245
+ });
246
+ }
247
+
248
+ cardSelect(event, element) {
249
+ if (this.type === 'radio') {
250
+ this.fieldOnChange(element.key);
251
+ } else if (this.type === 'checkbox') {
252
+ this.handleChangeMultiMode(event, element);
253
+ }
254
+ }
255
+ }
@@ -15,7 +15,6 @@ interface SemanticLinkProps extends PConnFieldProps {
15
15
  selector: 'app-semantic-link',
16
16
  templateUrl: './semantic-link.component.html',
17
17
  styleUrls: ['./semantic-link.component.scss'],
18
- standalone: true,
19
18
  imports: [CommonModule, forwardRef(() => ComponentMapperComponent)]
20
19
  })
21
20
  export class SemanticLinkComponent implements OnInit, OnDestroy {