@pega/angular-sdk-overrides 24.1.10 → 24.2.12

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 (125) hide show
  1. package/lib/designSystemExtension/alert-banner/alert-banner.component.ts +1 -1
  2. package/lib/designSystemExtension/case-create-stage/case-create-stage.component.ts +1 -1
  3. package/lib/designSystemExtension/material-case-summary/material-case-summary.component.scss +2 -1
  4. package/lib/designSystemExtension/material-case-summary/material-case-summary.component.ts +0 -1
  5. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.html +2 -2
  6. package/lib/designSystemExtension/material-details-fields/material-details-fields.component.ts +10 -1
  7. package/lib/designSystemExtension/operator/operator.component.html +1 -1
  8. package/lib/designSystemExtension/operator/operator.component.scss +10 -2
  9. package/lib/designSystemExtension/operator/operator.component.ts +5 -4
  10. package/lib/designSystemExtension/pulse/pulse.component.ts +7 -7
  11. package/lib/field/auto-complete/auto-complete.component.html +0 -1
  12. package/lib/field/auto-complete/auto-complete.component.ts +31 -15
  13. package/lib/field/check-box/check-box.component.html +4 -0
  14. package/lib/field/check-box/check-box.component.ts +11 -10
  15. package/lib/field/currency/currency.component.html +4 -4
  16. package/lib/field/currency/currency.component.ts +42 -19
  17. package/lib/field/date/date.component.html +3 -7
  18. package/lib/field/date/date.component.ts +22 -39
  19. package/lib/field/date-time/date-time.component.html +3 -4
  20. package/lib/field/date-time/date-time.component.ts +35 -16
  21. package/lib/field/decimal/decimal.component.html +4 -3
  22. package/lib/field/decimal/decimal.component.ts +47 -21
  23. package/lib/field/dropdown/dropdown.component.html +1 -0
  24. package/lib/field/dropdown/dropdown.component.ts +146 -18
  25. package/lib/field/email/email.component.ts +24 -4
  26. package/lib/field/group/group.component.ts +2 -2
  27. package/lib/field/integer/integer.component.ts +22 -4
  28. package/lib/field/list-view-action-buttons/list-view-action-buttons.component.html +1 -1
  29. package/lib/field/list-view-action-buttons/list-view-action-buttons.component.ts +3 -2
  30. package/lib/field/multiselect/multiselect.component.ts +15 -5
  31. package/lib/field/percentage/percentage.component.html +3 -3
  32. package/lib/field/percentage/percentage.component.ts +45 -20
  33. package/lib/field/phone/config-ext.json +1 -1
  34. package/lib/field/phone/phone.component.html +4 -2
  35. package/lib/field/phone/phone.component.ts +16 -26
  36. package/lib/field/radio-buttons/radio-buttons.component.html +3 -6
  37. package/lib/field/radio-buttons/radio-buttons.component.ts +9 -9
  38. package/lib/field/rich-text/rich-text.component.ts +19 -8
  39. package/lib/field/scalar-list/scalar-list.component.ts +3 -4
  40. package/lib/field/text/text.component.ts +8 -4
  41. package/lib/field/text-area/text-area.component.html +4 -1
  42. package/lib/field/text-area/text-area.component.ts +22 -5
  43. package/lib/field/text-input/text-input.component.ts +22 -4
  44. package/lib/field/time/time.component.html +2 -2
  45. package/lib/field/time/time.component.ts +35 -6
  46. package/lib/field/url/url.component.ts +22 -4
  47. package/lib/field/user-reference/user-reference.component.html +40 -46
  48. package/lib/field/user-reference/user-reference.component.ts +111 -20
  49. package/lib/infra/Containers/flow-container/flow-container.component.html +1 -1
  50. package/lib/infra/Containers/flow-container/flow-container.component.ts +25 -47
  51. package/lib/infra/Containers/flow-container/helpers.ts +2 -2
  52. package/lib/infra/Containers/modal-view-container/modal-view-container.component.html +1 -11
  53. package/lib/infra/Containers/modal-view-container/modal-view-container.component.ts +1 -8
  54. package/lib/infra/Containers/preview-view-container/preview-view-container.component.ts +1 -1
  55. package/lib/infra/Containers/view-container/helper.ts +22 -0
  56. package/lib/infra/Containers/view-container/view-container.component.ts +5 -17
  57. package/lib/infra/action-buttons/action-buttons.component.html +1 -1
  58. package/lib/infra/assignment/assignment.component.html +1 -1
  59. package/lib/infra/assignment/assignment.component.ts +82 -40
  60. package/lib/infra/assignment-card/assignment-card.component.html +1 -0
  61. package/lib/infra/defer-load/defer-load.component.ts +8 -5
  62. package/lib/infra/navbar/navbar.component.ts +3 -5
  63. package/lib/infra/reference/reference.component.ts +77 -90
  64. package/lib/infra/root-container/root-container.component.html +2 -15
  65. package/lib/infra/root-container/root-container.component.ts +27 -30
  66. package/lib/infra/stages/stages.component.scss +2 -2
  67. package/lib/infra/view/view.component.html +7 -20
  68. package/lib/infra/view/view.component.ts +20 -2
  69. package/lib/template/app-shell/app-shell.component.ts +20 -2
  70. package/lib/template/base/details-template-base.ts +67 -0
  71. package/lib/template/base/form-template-base.ts +16 -0
  72. package/lib/template/case-summary/case-summary.component.ts +1 -1
  73. package/lib/template/case-view/case-view.component.html +4 -4
  74. package/lib/template/case-view/case-view.component.ts +8 -13
  75. package/lib/template/confirmation/confirmation.component.html +1 -1
  76. package/lib/template/confirmation/confirmation.component.ts +1 -1
  77. package/lib/template/data-reference/data-reference.component.ts +36 -40
  78. package/lib/template/default-form/default-form.component.html +0 -4
  79. package/lib/template/default-form/default-form.component.ts +41 -24
  80. package/lib/template/details/details.component.ts +7 -41
  81. package/lib/template/details-narrow-wide/details-narrow-wide.component.ts +6 -39
  82. package/lib/template/details-one-column/details-one-column.component.ts +7 -42
  83. package/lib/template/details-sub-tabs/details-sub-tabs.component.html +1 -2
  84. package/lib/template/details-sub-tabs/details-sub-tabs.component.ts +5 -37
  85. package/lib/template/details-three-column/details-three-column.component.ts +7 -43
  86. package/lib/template/details-two-column/details-two-column.component.ts +8 -44
  87. package/lib/template/details-wide-narrow/details-wide-narrow.component.ts +7 -42
  88. package/lib/template/dynamic-tabs/dynamic-tabs.component.html +3 -0
  89. package/lib/template/dynamic-tabs/dynamic-tabs.component.ts +8 -3
  90. package/lib/template/field-group-template/field-group-template.component.html +7 -7
  91. package/lib/template/field-group-template/field-group-template.component.scss +8 -0
  92. package/lib/template/field-group-template/field-group-template.component.ts +68 -47
  93. package/lib/template/field-value-list/field-value-list.component.html +2 -2
  94. package/lib/template/field-value-list/field-value-list.component.scss +6 -1
  95. package/lib/template/inline-dashboard-page/inline-dashboard-page.component.ts +2 -2
  96. package/lib/template/list-view/list-view.component.html +6 -1
  97. package/lib/template/list-view/list-view.component.scss +11 -0
  98. package/lib/template/list-view/list-view.component.ts +25 -7
  99. package/lib/template/list-view/listViewHelpers.ts +3 -6
  100. package/lib/template/list-view/utils.ts +2 -5
  101. package/lib/template/narrow-wide-form/narrow-wide-form.component.ts +1 -1
  102. package/lib/template/one-column/one-column.component.ts +4 -3
  103. package/lib/template/one-column-tab/one-column-tab.component.ts +1 -1
  104. package/lib/template/page/page.component.ts +1 -1
  105. package/lib/template/promoted-filters/promoted-filters.component.ts +1 -1
  106. package/lib/template/repeating-structures/repeating-structures.component.ts +1 -1
  107. package/lib/template/simple-table-manual/helpers.ts +10 -8
  108. package/lib/template/simple-table-manual/simple-table-manual.component.html +25 -6
  109. package/lib/template/simple-table-manual/simple-table-manual.component.scss +12 -3
  110. package/lib/template/simple-table-manual/simple-table-manual.component.ts +77 -37
  111. package/lib/template/simple-table-select/simple-table-select.component.ts +3 -3
  112. package/lib/template/three-column/three-column.component.ts +4 -3
  113. package/lib/template/two-column/two-column.component.ts +4 -3
  114. package/lib/template/two-column-tab/two-column-tab.component.ts +1 -1
  115. package/lib/template/utils.ts +16 -0
  116. package/lib/template/wide-narrow-form/wide-narrow-form.component.ts +4 -3
  117. package/lib/template/wide-narrow-page/wide-narrow-page.component.ts +1 -1
  118. package/lib/template/wss-nav-bar/wss-nav-bar.component.ts +3 -3
  119. package/lib/widget/attachment/attachment.component.ts +7 -9
  120. package/lib/widget/feed-container/feed-container.component.ts +7 -9
  121. package/lib/widget/file-utility/file-utility.component.ts +2 -5
  122. package/lib/widget/todo/todo.component.html +5 -6
  123. package/lib/widget/todo/todo.component.scss +9 -0
  124. package/lib/widget/todo/todo.component.ts +95 -84
  125. package/package.json +1 -1
@@ -1,9 +1,11 @@
1
1
  import { Component, OnInit, Input, forwardRef, OnDestroy } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
+ import { FormGroup } from '@angular/forms';
3
4
  import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
4
5
  import { Utils } from '@pega/angular-sdk-components';
5
6
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
6
7
  import { PConnFieldProps } from '@pega/angular-sdk-components';
8
+ import { format } from '@pega/angular-sdk-components';
7
9
 
8
10
  interface TextProps extends PConnFieldProps {
9
11
  // If any, enter additional props that only exist on Text here
@@ -18,6 +20,7 @@ interface TextProps extends PConnFieldProps {
18
20
  })
19
21
  export class TextComponent implements OnInit, OnDestroy {
20
22
  @Input() pConn$: typeof PConnect;
23
+ @Input() formGroup$: FormGroup;
21
24
  @Input() formatAs$: string;
22
25
 
23
26
  // Used with AngularPConnect
@@ -97,8 +100,9 @@ export class TextComponent implements OnInit, OnDestroy {
97
100
  break;
98
101
  case 'time':
99
102
  if (this.value$) {
100
- const timeParts = this.value$.split(':');
101
- this.formattedValue$ = `${timeParts[0]}:${timeParts[1]}`;
103
+ this.formattedValue$ = format(this.value$, 'timeonly', {
104
+ format: 'hh:mm A'
105
+ });
102
106
  } else {
103
107
  this.formattedValue$ = '';
104
108
  }
@@ -142,7 +146,7 @@ export class TextComponent implements OnInit, OnDestroy {
142
146
  generateDateTime(sVal): string {
143
147
  if (!sVal) return '';
144
148
  if (sVal.length === 10) return this.generateDate(sVal);
145
- const value = sVal.substring(0, sVal.length - 1);
149
+ // const value = sVal.substring(0, sVal.length - 1);
146
150
  // value = new Intl.DateTimeFormat('default', {
147
151
  // year: 'numeric',
148
152
  // month: 'numeric',
@@ -153,6 +157,6 @@ export class TextComponent implements OnInit, OnDestroy {
153
157
  // hour12: true,
154
158
  // }).format(new Date(value))
155
159
 
156
- return this.utils.generateDateTime(value, 'DateTime-Long-YYYY-Custom');
160
+ return this.utils.generateDateTime(sVal, 'DateTime-Long-YYYY-Custom');
157
161
  }
158
162
  }
@@ -2,10 +2,11 @@
2
2
  <component-mapper *ngIf="bVisible$ !== false" name="FieldValueList" [props]="{ label$, value$, displayMode$ }"></component-mapper>
3
3
  </div>
4
4
  <ng-template #noDisplayMode>
5
- <div *ngIf="!bReadonly$ && bHasForm$; else noEdit">
5
+ <div *ngIf="bHasForm$; else noEdit">
6
6
  <div [formGroup]="formGroup$">
7
7
  <div *ngIf="bVisible$">
8
8
  <mat-form-field class="psdk-full-width" subscriptSizing="dynamic" [hintLabel]="helperText">
9
+ <mat-label>{{ label$ }}</mat-label>
9
10
  <textarea
10
11
  matInput
11
12
  rows="5"
@@ -15,8 +16,10 @@
15
16
  [value]="value$"
16
17
  [required]="bRequired$"
17
18
  [disabled]="bDisabled$"
19
+ [readonly]="bReadonly$"
18
20
  [formControl]="fieldControl"
19
21
  (change)="fieldOnChange($event)"
22
+ (blur)="fieldOnBlur($event)"
20
23
  ></textarea>
21
24
  <mat-error *ngIf="fieldControl.invalid">{{ getErrorMessage() }}</mat-error>
22
25
  </mat-form-field>
@@ -8,6 +8,7 @@ import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-c
8
8
  import { Utils } from '@pega/angular-sdk-components';
9
9
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
10
10
  import { PConnFieldProps } from '@pega/angular-sdk-components';
11
+ import { handleEvent } from '@pega/angular-sdk-components';
11
12
 
12
13
  interface TextAreaProps extends PConnFieldProps {
13
14
  // If any, enter additional props that only exist on TextArea here
@@ -44,6 +45,8 @@ export class TextAreaComponent implements OnInit, OnDestroy {
44
45
  helperText: string;
45
46
 
46
47
  fieldControl = new FormControl('', null);
48
+ actionsApi: Object;
49
+ propName: string;
47
50
 
48
51
  constructor(
49
52
  private angularPConnect: AngularPConnectService,
@@ -113,6 +116,9 @@ export class TextAreaComponent implements OnInit, OnDestroy {
113
116
  this.label$ = this.configProps$.label;
114
117
  this.helperText = this.configProps$.helperText;
115
118
 
119
+ this.actionsApi = this.pConn$.getActionsApi();
120
+ this.propName = this.pConn$.getStateProps().value;
121
+
116
122
  // timeout and detectChanges to avoid ExpressionChangedAfterItHasBeenCheckedError
117
123
  setTimeout(() => {
118
124
  if (this.configProps$.required != null) {
@@ -140,7 +146,7 @@ export class TextAreaComponent implements OnInit, OnDestroy {
140
146
  this.bReadonly$ = this.utils.getBooleanValue(this.configProps$.readOnly);
141
147
  }
142
148
 
143
- this.componentReference = (this.pConn$.getStateProps() as any).value;
149
+ this.componentReference = this.pConn$.getStateProps().value;
144
150
 
145
151
  // trigger display of error message with field control
146
152
  if (this.angularPConnectData.validateMessage != null && this.angularPConnectData.validateMessage != '') {
@@ -154,13 +160,24 @@ export class TextAreaComponent implements OnInit, OnDestroy {
154
160
  }
155
161
 
156
162
  fieldOnChange(event: any) {
157
- // PConnect wants to use changeHandler for onChange
158
- this.angularPConnectData.actions?.onChange(this, event);
163
+ const oldVal = this.value$ ?? '';
164
+ const isValueChanged = event.target.value.toString() !== oldVal.toString();
165
+
166
+ if (isValueChanged) {
167
+ this.pConn$.clearErrorMessages({
168
+ property: this.propName
169
+ });
170
+ }
159
171
  }
160
172
 
161
173
  fieldOnBlur(event: any) {
162
- // PConnect wants to use eventHandler for onBlur
163
- this.angularPConnectData.actions?.onBlur(this, event);
174
+ const oldVal = this.value$ ?? '';
175
+ const isValueChanged = event.target.value.toString() !== oldVal.toString();
176
+
177
+ if (isValueChanged) {
178
+ const value = event?.target?.value;
179
+ handleEvent(this.actionsApi, 'changeNblur', this.propName, value);
180
+ }
164
181
  }
165
182
 
166
183
  getErrorMessage() {
@@ -8,6 +8,7 @@ import { AngularPConnectService, AngularPConnectData } from '@pega/angular-sdk-c
8
8
  import { Utils } from '@pega/angular-sdk-components';
9
9
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
10
10
  import { PConnFieldProps } from '@pega/angular-sdk-components';
11
+ import { handleEvent } from '@pega/angular-sdk-components';
11
12
 
12
13
  interface TextInputProps extends PConnFieldProps {
13
14
  // If any, enter additional props that only exist on TextInput here
@@ -44,6 +45,8 @@ export class TextInputComponent implements OnInit, OnDestroy {
44
45
  placeholder: string;
45
46
 
46
47
  fieldControl = new FormControl('', null);
48
+ actionsApi: Object;
49
+ propName: string;
47
50
 
48
51
  constructor(
49
52
  private angularPConnect: AngularPConnectService,
@@ -113,7 +116,10 @@ export class TextInputComponent implements OnInit, OnDestroy {
113
116
  this.label$ = this.configProps$.label;
114
117
  this.displayMode$ = this.configProps$.displayMode;
115
118
 
116
- this.componentReference = (this.pConn$.getStateProps() as any).value;
119
+ this.componentReference = this.pConn$.getStateProps().value;
120
+
121
+ this.actionsApi = this.pConn$.getActionsApi();
122
+ this.propName = this.pConn$.getStateProps().value;
117
123
 
118
124
  if (this.configProps$.visibility != null) {
119
125
  this.bVisible$ = this.utils.getBooleanValue(this.configProps$.visibility);
@@ -156,12 +162,24 @@ export class TextInputComponent implements OnInit, OnDestroy {
156
162
  }
157
163
 
158
164
  fieldOnChange(event: any) {
159
- this.angularPConnectData.actions?.onChange(this, event);
165
+ const oldVal = this.value$ ?? '';
166
+ const isValueChanged = event.target.value.toString() !== oldVal.toString();
167
+
168
+ if (isValueChanged) {
169
+ this.pConn$.clearErrorMessages({
170
+ property: this.propName
171
+ });
172
+ }
160
173
  }
161
174
 
162
175
  fieldOnBlur(event: any) {
163
- // PConnect wants to use eventHandler for onBlur
164
- this.angularPConnectData.actions?.onBlur(this, event);
176
+ const oldVal = this.value$ ?? '';
177
+ const isValueChanged = event.target.value.toString() !== oldVal.toString();
178
+
179
+ if (isValueChanged) {
180
+ const value = event?.target?.value;
181
+ handleEvent(this.actionsApi, 'changeNblur', this.propName, value);
182
+ }
165
183
  }
166
184
 
167
185
  getErrorMessage() {
@@ -1,5 +1,5 @@
1
1
  <div *ngIf="displayMode$; else noDisplayMode">
2
- <component-mapper *ngIf="bVisible$ !== false" name="FieldValueList" [props]="{ label$, value$, displayMode$ }"></component-mapper>
2
+ <component-mapper *ngIf="bVisible$ !== false" name="FieldValueList" [props]="{ label$, value$: formattedValue$, displayMode$ }"></component-mapper>
3
3
  </div>
4
4
  <ng-template #noDisplayMode>
5
5
  <div *ngIf="!bReadonly$ && bHasForm$; else noEdit">
@@ -23,5 +23,5 @@
23
23
  </div>
24
24
  </ng-template>
25
25
  <ng-template #noEdit>
26
- <component-mapper *ngIf="bVisible$ !== false" name="Text" [props]="{ pConn$, formatAs$: 'text' }"></component-mapper>
26
+ <component-mapper *ngIf="bVisible$ !== false" name="Text" [props]="{ pConn$, formatAs$: 'time' }"></component-mapper>
27
27
  </ng-template>
@@ -8,6 +8,8 @@ import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-c
8
8
  import { Utils } from '@pega/angular-sdk-components';
9
9
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
10
10
  import { PConnFieldProps } from '@pega/angular-sdk-components';
11
+ import { handleEvent } from '@pega/angular-sdk-components';
12
+ import { format } from '@pega/angular-sdk-components';
11
13
 
12
14
  interface TimeProps extends PConnFieldProps {
13
15
  // If any, enter additional props that only exist on Time here
@@ -43,6 +45,9 @@ export class TimeComponent implements OnInit, OnDestroy {
43
45
  placeholder: string;
44
46
 
45
47
  fieldControl = new FormControl('', null);
48
+ actionsApi: Object;
49
+ propName: string;
50
+ formattedValue$: any;
46
51
 
47
52
  constructor(
48
53
  private angularPConnect: AngularPConnectService,
@@ -111,6 +116,9 @@ export class TimeComponent implements OnInit, OnDestroy {
111
116
  this.helperText = this.configProps$.helperText;
112
117
  this.placeholder = this.configProps$.placeholder || '';
113
118
 
119
+ this.actionsApi = this.pConn$.getActionsApi();
120
+ this.propName = this.pConn$.getStateProps().value;
121
+
114
122
  // timeout and detectChanges to avoid ExpressionChangedAfterItHasBeenCheckedError
115
123
  setTimeout(() => {
116
124
  if (this.configProps$.required != null) {
@@ -119,6 +127,12 @@ export class TimeComponent implements OnInit, OnDestroy {
119
127
  this.cdRef.detectChanges();
120
128
  });
121
129
 
130
+ if (this.displayMode$ === 'DISPLAY_ONLY' || this.displayMode$ === 'STACKED_LARGE_VAL') {
131
+ this.formattedValue$ = format(this.value$, 'timeonly', {
132
+ format: 'hh:mm A'
133
+ });
134
+ }
135
+
122
136
  if (this.configProps$.visibility != null) {
123
137
  this.bVisible$ = this.utils.getBooleanValue(this.configProps$.visibility);
124
138
  }
@@ -138,7 +152,7 @@ export class TimeComponent implements OnInit, OnDestroy {
138
152
  this.bReadonly$ = this.utils.getBooleanValue(this.configProps$.readOnly);
139
153
  }
140
154
 
141
- this.componentReference = (this.pConn$.getStateProps() as any).value;
155
+ this.componentReference = this.pConn$.getStateProps().value;
142
156
 
143
157
  // trigger display of error message with field control
144
158
  if (this.angularPConnectData.validateMessage != null && this.angularPConnectData.validateMessage != '') {
@@ -152,14 +166,29 @@ export class TimeComponent implements OnInit, OnDestroy {
152
166
  }
153
167
 
154
168
  fieldOnChange(event: any) {
155
- event.value = event.target.value;
156
- this.angularPConnectData.actions?.onChange(this, event);
169
+ const oldVal = this.value$ ?? '';
170
+ const isValueChanged = event.target.value.toString() !== oldVal.toString();
171
+
172
+ if (isValueChanged) {
173
+ this.pConn$.clearErrorMessages({
174
+ property: this.propName
175
+ });
176
+ }
157
177
  }
158
178
 
159
179
  fieldOnBlur(event: any) {
160
- // PConnect wants to use eventHandler for onBlur
161
- event.value = event.target.value;
162
- this.angularPConnectData.actions?.onBlur(this, event);
180
+ const oldVal = this.value$ ?? '';
181
+ const isValueChanged = event?.target?.value.toString() !== oldVal.toString();
182
+
183
+ if (isValueChanged) {
184
+ let value = event?.target?.value;
185
+ const hhmmPattern = /^\d{2}:\d{2}$/;
186
+ if (hhmmPattern.test(value)) {
187
+ value = `${value}:00`; // append ":00"
188
+ }
189
+
190
+ handleEvent(this.actionsApi, 'changeNblur', this.propName, value);
191
+ }
163
192
  }
164
193
 
165
194
  getErrorMessage() {
@@ -8,6 +8,7 @@ import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-c
8
8
  import { Utils } from '@pega/angular-sdk-components';
9
9
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
10
10
  import { PConnFieldProps } from '@pega/angular-sdk-components';
11
+ import { handleEvent } from '@pega/angular-sdk-components';
11
12
 
12
13
  interface URLProps extends PConnFieldProps {
13
14
  // If any, enter additional props that only exist on URL here
@@ -43,6 +44,8 @@ export class UrlComponent implements OnInit, OnDestroy {
43
44
  placeholder: string;
44
45
 
45
46
  fieldControl = new FormControl('', null);
47
+ actionsApi: Object;
48
+ propName: string;
46
49
 
47
50
  constructor(
48
51
  private angularPConnect: AngularPConnectService,
@@ -113,6 +116,9 @@ export class UrlComponent implements OnInit, OnDestroy {
113
116
  this.helperText = this.configProps$.helperText;
114
117
  this.placeholder = this.configProps$.placeholder || '';
115
118
 
119
+ this.actionsApi = this.pConn$.getActionsApi();
120
+ this.propName = this.pConn$.getStateProps().value;
121
+
116
122
  // timeout and detectChanges to avoid ExpressionChangedAfterItHasBeenCheckedError
117
123
  setTimeout(() => {
118
124
  if (this.configProps$.required != null) {
@@ -140,7 +146,7 @@ export class UrlComponent implements OnInit, OnDestroy {
140
146
  this.bReadonly$ = this.utils.getBooleanValue(this.configProps$.readOnly);
141
147
  }
142
148
 
143
- this.componentReference = (this.pConn$.getStateProps() as any).value;
149
+ this.componentReference = this.pConn$.getStateProps().value;
144
150
 
145
151
  // trigger display of error message with field control
146
152
  if (this.angularPConnectData.validateMessage != null && this.angularPConnectData.validateMessage != '') {
@@ -154,12 +160,24 @@ export class UrlComponent implements OnInit, OnDestroy {
154
160
  }
155
161
 
156
162
  fieldOnChange(event: any) {
157
- this.angularPConnectData.actions?.onChange(this, event);
163
+ const oldVal = this.value$ ?? '';
164
+ const isValueChanged = event.target.value.toString() !== oldVal.toString();
165
+
166
+ if (isValueChanged) {
167
+ this.pConn$.clearErrorMessages({
168
+ property: this.propName
169
+ });
170
+ }
158
171
  }
159
172
 
160
173
  fieldOnBlur(event: any) {
161
- // PConnect wants to use eventHandler for onBlur
162
- this.angularPConnectData.actions?.onBlur(this, event);
174
+ const oldVal = this.value$ ?? '';
175
+ const isValueChanged = event.target.value.toString() !== oldVal.toString();
176
+
177
+ if (isValueChanged) {
178
+ const value = event?.target?.value;
179
+ handleEvent(this.actionsApi, 'changeNblur', this.propName, value);
180
+ }
163
181
  }
164
182
 
165
183
  getErrorMessage() {
@@ -1,53 +1,47 @@
1
- <div class="psdk-user-reference">
1
+ <div>
2
2
  <div *ngIf="displayMode$; else noDisplayMode">
3
3
  <component-mapper name="FieldValueList" [props]="{ label$, value$, displayMode$ }"></component-mapper>
4
4
  </div>
5
5
  <ng-template #noDisplayMode>
6
- <div *ngIf="type === 'operator'">
7
- <component-mapper name="Operator" [props]="{ pConn$ }"></component-mapper>
8
- </div>
9
- <div [formGroup]="formGroup$" *ngIf="type === 'dropdown'">
10
- <mat-form-field class="psdk-full-width" subscriptSizing="dynamic" [hintLabel]="helperText">
11
- <mat-select
12
- [value]="value$"
13
- [required]="bRequired$"
14
- [formControl]="fieldControl"
15
- [attr.data-test-id]="testId"
16
- (selectionChange)="fieldOnChange($event)"
17
- >
18
- <mat-option *ngFor="let opt of options$" [value]="opt.key">
19
- {{ opt.value }}
20
- </mat-option>
21
- </mat-select>
22
- <mat-label>{{ label$ }}</mat-label>
23
- <mat-error *ngIf="fieldControl.invalid">
24
- {{ getErrorMessage() }}
25
- </mat-error>
26
- </mat-form-field>
27
- </div>
28
- <div [formGroup]="formGroup$" *ngIf="type === 'searchbox'">
29
- <mat-form-field class="psdk-full-width" subscriptSizing="dynamic" [hintLabel]="helperText">
30
- <mat-label>{{ label$ }}</mat-label>
31
- <input
32
- matInput
33
- [placeholder]="placeholder"
34
- [formControl]="fieldControl"
35
- [value]="value$"
36
- [required]="bRequired$"
37
- [matAutocomplete]="auto"
38
- [attr.data-test-id]="testId"
39
- (change)="fieldOnChange($event)"
40
- (blur)="fieldOnBlur($event)"
41
- />
42
- <mat-autocomplete #auto="matAutocomplete">
43
- <mat-option *ngFor="let opt of filteredOptions | async" [value]="opt.value">
44
- <span>{{ opt.value }}</span>
45
- </mat-option>
46
- </mat-autocomplete>
47
- <mat-error *ngIf="fieldControl.invalid">
48
- {{ getErrorMessage() }}
49
- </mat-error>
50
- </mat-form-field>
6
+ <div class="psdk-user-reference">
7
+ <div *ngIf="this.userID$ && type === 'operator'">
8
+ <component-mapper name="Operator" [props]="{ pConn$, name$: userName$ }"></component-mapper>
9
+ </div>
10
+ <div [formGroup]="formGroup$" *ngIf="type === 'dropdown'">
11
+ <mat-form-field class="psdk-full-width" subscriptSizing="dynamic" [hintLabel]="helperText">
12
+ <mat-select [required]="bRequired$" [formControl]="fieldControl" [attr.data-test-id]="testId" (selectionChange)="fieldOnChange($event)">
13
+ <mat-option *ngFor="let opt of options$" [value]="opt.key">
14
+ {{ opt.value }}
15
+ </mat-option>
16
+ </mat-select>
17
+ <mat-label>{{ label$ }}</mat-label>
18
+ <mat-error *ngIf="fieldControl.invalid">
19
+ {{ getErrorMessage() }}
20
+ </mat-error>
21
+ </mat-form-field>
22
+ </div>
23
+ <div [formGroup]="formGroup$" *ngIf="type === 'searchbox'">
24
+ <mat-form-field class="psdk-full-width" subscriptSizing="dynamic" [hintLabel]="helperText">
25
+ <mat-label>{{ label$ }}</mat-label>
26
+ <input
27
+ matInput
28
+ [placeholder]="placeholder"
29
+ [formControl]="fieldControl"
30
+ [required]="bRequired$"
31
+ [matAutocomplete]="auto"
32
+ [attr.data-test-id]="testId"
33
+ (blur)="fieldOnBlur($event)"
34
+ />
35
+ <mat-autocomplete #auto="matAutocomplete" autoActiveFirstOption (optionSelected)="optionChanged($event)">
36
+ <mat-option *ngFor="let opt of filteredOptions | async" [value]="opt.value">
37
+ <span>{{ opt.value }}</span>
38
+ </mat-option>
39
+ </mat-autocomplete>
40
+ <mat-error *ngIf="fieldControl.invalid">
41
+ {{ getErrorMessage() }}
42
+ </mat-error>
43
+ </mat-form-field>
44
+ </div>
51
45
  </div>
52
46
  </ng-template>
53
47
  </div>
@@ -11,6 +11,7 @@ import { Utils } from '@pega/angular-sdk-components';
11
11
  import { ComponentMapperComponent } from '@pega/angular-sdk-components';
12
12
  import { PConnFieldProps } from '@pega/angular-sdk-components';
13
13
  import { map, Observable, startWith } from 'rxjs';
14
+ import { handleEvent } from '@pega/angular-sdk-components';
14
15
 
15
16
  const OPERATORS_DP = 'D_pyGetOperatorsForCurrentApplication';
16
17
  const DROPDOWN_LIST = 'Drop-down list';
@@ -22,6 +23,7 @@ interface UserReferenceProps extends Omit<PConnFieldProps, 'value'> {
22
23
  value?: any;
23
24
  showAsFormattedText?: boolean;
24
25
  additionalProps?: object;
26
+ onRecordChange?: any;
25
27
  }
26
28
 
27
29
  @Component({
@@ -63,6 +65,9 @@ export class UserReferenceComponent implements OnInit, OnDestroy {
63
65
  filterValue = '';
64
66
 
65
67
  fieldControl = new FormControl('', null);
68
+ actionsApi: Object;
69
+ propName: string;
70
+ onRecordChange: any;
66
71
 
67
72
  constructor(
68
73
  private angularPConnect: AngularPConnectService,
@@ -80,11 +85,11 @@ export class UserReferenceComponent implements OnInit, OnDestroy {
80
85
  if (this.formGroup$) {
81
86
  // add control to formGroup
82
87
  this.formGroup$.addControl(this.controlName$, this.fieldControl);
83
- this.fieldControl.setValue(this.value$);
88
+ this.fieldControl.setValue(this.getValue(this.value$));
84
89
  }
85
90
 
86
91
  this.filteredOptions = this.fieldControl.valueChanges.pipe(
87
- startWith(''),
92
+ startWith(this.getValue(this.value$) || ''),
88
93
  map(value => this._filter(value || ''))
89
94
  );
90
95
  }
@@ -123,6 +128,21 @@ export class UserReferenceComponent implements OnInit, OnDestroy {
123
128
  return this.options$?.filter(option => option.value?.toLowerCase().includes(filterVal));
124
129
  }
125
130
 
131
+ isUserNameAvailable = user => {
132
+ return typeof user === 'object' && user !== null && user.userName;
133
+ };
134
+
135
+ getUserName = user => {
136
+ return user.userName;
137
+ };
138
+
139
+ getValue = user => {
140
+ if (this.displayAs$ === DROPDOWN_LIST) {
141
+ return this.utils.getUserId(user) || this.getUserName(user);
142
+ }
143
+ return this.isUserNameAvailable(user) ? this.getUserName(user) : this.utils.getUserId(user);
144
+ };
145
+
126
146
  async checkAndUpdate() {
127
147
  // Should always check the bridge to see if the component should
128
148
  // update itself (re-render)
@@ -137,6 +157,7 @@ export class UserReferenceComponent implements OnInit, OnDestroy {
137
157
  async updateSelf() {
138
158
  const props = this.pConn$.getConfigProps() as UserReferenceProps;
139
159
  this.testId = props.testId;
160
+ this.onRecordChange = props?.onRecordChange;
140
161
 
141
162
  const { label, displayAs, value, showAsFormattedText, helperText, placeholder, displayMode } = props;
142
163
 
@@ -147,34 +168,35 @@ export class UserReferenceComponent implements OnInit, OnDestroy {
147
168
  this.placeholder = placeholder || '';
148
169
  this.displayMode$ = displayMode;
149
170
 
171
+ if (value && typeof value === 'object') {
172
+ this.value$ = value.userName ? value.userName : '';
173
+ } else {
174
+ this.value$ = value || '';
175
+ }
176
+
150
177
  const { readOnly, required } = props;
151
178
  [this.bReadonly$, this.bRequired$] = [readOnly, required].map(prop => prop === true || (typeof prop === 'string' && prop === 'true'));
152
179
 
153
- const isUserNameAvailable = user => {
154
- return typeof user === 'object' && user !== null && user.userName;
155
- };
180
+ this.actionsApi = this.pConn$.getActionsApi();
181
+ this.propName = this.pConn$.getStateProps().value;
156
182
 
157
183
  this.userID$ = this.utils.getUserId(value);
158
184
 
159
185
  if (this.userID$ && this.bReadonly$ && this.showAsFormattedText$) {
160
- if (isUserNameAvailable(value)) {
186
+ if (this.isUserNameAvailable(value)) {
161
187
  this.userName$ = value.userName;
162
188
  } else {
163
189
  // if same user ref field is referred in view as editable & readonly formatted text
164
190
  // referenced users won't be available, so get user details from dx api
165
- const { getOperatorDetails } = PCore.getUserApi();
166
- getOperatorDetails(this.userID$).then((resp: any) => {
167
- if (resp.data && resp.data.pyOperatorInfo && resp.data.pyOperatorInfo.pyUserName) {
168
- this.userName$ = resp.data.pyOperatorInfo.pyUserName;
169
- }
170
- });
191
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
192
+ this.userName$ = await getUserName(this.pConn$, this.userID$);
171
193
  }
172
194
  } else if (displayAs === DROPDOWN_LIST || displayAs === SEARCH_BOX) {
173
195
  const queryPayload = {
174
196
  dataViewName: OPERATORS_DP
175
197
  };
176
198
  try {
177
- const resp: any = await PCore.getRestClient().invokeRestApi('getListData', { queryPayload } as any, ''); // 3rd arg empty string until typedef marked correctly
199
+ const resp = await PCore.getRestClient().invokeRestApi('getListData', { queryPayload }, ''); // 3rd arg empty string until typedef marked correctly
178
200
  if (resp?.data) {
179
201
  const ddDataSource = resp.data.data.map(listItem => ({
180
202
  key: listItem.pyUserIdentifier,
@@ -195,7 +217,13 @@ export class UserReferenceComponent implements OnInit, OnDestroy {
195
217
  if (event?.target) {
196
218
  this.filterValue = (event.target as HTMLInputElement).value;
197
219
  }
198
- this.angularPConnectData.actions?.onChange(this, event);
220
+ const value = event?.value;
221
+ handleEvent(this.actionsApi, 'change', this.propName, value);
222
+ }
223
+
224
+ optionChanged(event: any) {
225
+ const value = event?.option?.value;
226
+ handleEvent(this.actionsApi, 'change', this.propName, value);
199
227
  }
200
228
 
201
229
  fieldOnBlur(event: any) {
@@ -204,12 +232,12 @@ export class UserReferenceComponent implements OnInit, OnDestroy {
204
232
  const index = this.options$?.findIndex(element => element.value === event.target.value);
205
233
  key = index > -1 ? (key = this.options$[index].key) : event.target.value;
206
234
  }
207
-
208
- const eve = {
209
- value: key
210
- };
211
- // PConnect wants to use eventHandler for onBlur
212
- this.angularPConnectData.actions?.onChange(this, eve);
235
+ const value = key;
236
+ handleEvent(this.actionsApi, 'changeNblur', this.propName, value);
237
+ if (this.onRecordChange) {
238
+ event.target.value = value;
239
+ this.onRecordChange(event);
240
+ }
213
241
  }
214
242
 
215
243
  getErrorMessage() {
@@ -229,3 +257,66 @@ export class UserReferenceComponent implements OnInit, OnDestroy {
229
257
  return errMessage;
230
258
  }
231
259
  }
260
+
261
+ const buildColumnForDisplayValue = dataObj => {
262
+ if (dataObj.columns) {
263
+ dataObj.columns = dataObj.columns.map(column => {
264
+ const tempColObj = { ...column };
265
+ if (tempColObj.key === 'true') {
266
+ tempColObj.useForSearch = true;
267
+ } else {
268
+ tempColObj.useForSearch = false;
269
+ }
270
+ return tempColObj;
271
+ });
272
+ }
273
+ };
274
+
275
+ function getUserName(pConn, userId = ''): Promise<string> {
276
+ return new Promise(resolve => {
277
+ const { parameters = {}, referenceList } = pConn.getConfigProps();
278
+ const contextName = pConn.getContextName();
279
+
280
+ // eslint-disable-next-line @typescript-eslint/no-shadow
281
+ const OPERATORS_DP = referenceList || PCore.getEnvironmentInfo().getDefaultOperatorDP() || '';
282
+
283
+ const columns = [
284
+ {
285
+ value: 'pyUserName',
286
+ display: 'true',
287
+ useForSearch: true,
288
+ primary: 'true'
289
+ },
290
+ {
291
+ value: 'pyUserIdentifier',
292
+ setProperty: 'Associated property',
293
+ key: 'true',
294
+ display: 'true',
295
+ secondary: 'true',
296
+ useForSearch: true
297
+ }
298
+ ];
299
+
300
+ const dataConfig: any = {
301
+ dataSource: OPERATORS_DP,
302
+ parameters,
303
+ matchPosition: 'equals',
304
+ listType: 'datapage',
305
+ columns,
306
+ cacheLifeSpan: 'form',
307
+ deferDatasource: false,
308
+ maxResultsDisplay: '1',
309
+ ignoreCase: true
310
+ };
311
+
312
+ PCore.getDataApi()
313
+ .init(dataConfig, contextName)
314
+ .then(dataApiObj => {
315
+ buildColumnForDisplayValue(dataApiObj);
316
+ dataApiObj.registerForBufferedCall({ waitTime: 50 });
317
+ dataApiObj.fetchData(userId).then((response: any) => {
318
+ resolve(response.data?.[0]?.pyUserName || userId);
319
+ });
320
+ });
321
+ });
322
+ }