@pega/angular-sdk-overrides 0.24.9 → 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
@@ -0,0 +1,385 @@
1
+ import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
4
+ import { MatFormFieldModule } from '@angular/material/form-field';
5
+ import { MatInputModule } from '@angular/material/input';
6
+ import { MatAutocompleteModule } from '@angular/material/autocomplete';
7
+ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
8
+ import { MatIconModule } from '@angular/material/icon';
9
+ import { MatButtonModule } from '@angular/material/button';
10
+ import { GoogleMapsModule } from '@angular/google-maps';
11
+
12
+ import { debounceTime, from, interval, of, switchMap } from 'rxjs';
13
+
14
+ import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
15
+ import { GoogleMapsLoaderService } from '@pega/angular-sdk-components';
16
+ import { Utils } from '@pega/angular-sdk-components';
17
+ import { handleEvent } from '@pega/angular-sdk-components';
18
+
19
+ import { PConnFieldProps } from '@pega/angular-sdk-components';
20
+
21
+ interface LocationProps extends PConnFieldProps {
22
+ coordinates: string;
23
+ showMap: boolean;
24
+ onlyCoordinates: boolean;
25
+ showMapReadOnly: boolean;
26
+ }
27
+
28
+ @Component({
29
+ selector: 'app-location',
30
+ imports: [
31
+ CommonModule,
32
+ GoogleMapsModule,
33
+ MatAutocompleteModule,
34
+ MatButtonModule,
35
+ MatFormFieldModule,
36
+ MatIconModule,
37
+ MatInputModule,
38
+ MatProgressSpinnerModule,
39
+ ReactiveFormsModule
40
+ ],
41
+ templateUrl: './location.component.html',
42
+ styleUrl: './location.component.scss'
43
+ })
44
+ export class LocationComponent implements OnInit, OnDestroy {
45
+ @Input() pConn$: typeof PConnect;
46
+ @Input() formGroup$: FormGroup;
47
+
48
+ private autocompleteService!: google.maps.places.AutocompleteService;
49
+ private geocoder!: google.maps.Geocoder;
50
+
51
+ // Dom variables
52
+ mapReady = false;
53
+ isLocating = false;
54
+ searchControl = new FormControl('');
55
+ showMap = true;
56
+ filteredOptions: string[] = [];
57
+ center: google.maps.LatLngLiteral;
58
+ markerPosition: google.maps.LatLngLiteral | null = null;
59
+
60
+ // Used with AngularPConnect
61
+ angularPConnectData: AngularPConnectData = {};
62
+ configProps$: LocationProps;
63
+ label$ = '';
64
+ onlyCoordinates: boolean;
65
+ coordinates: string;
66
+ bRequired$ = false;
67
+ bReadonly$ = false;
68
+ showMapReadOnly$: boolean;
69
+ bDisabled$ = false;
70
+ bVisible$ = true;
71
+ controlName$: string;
72
+ bHasForm$ = true;
73
+ testId = '';
74
+ helperText: string;
75
+ placeholder: string;
76
+ actionsApi: Object;
77
+ valueProp: string;
78
+ coordinatesProp: string;
79
+
80
+ constructor(
81
+ private loader: GoogleMapsLoaderService,
82
+ private angularPConnect: AngularPConnectService,
83
+ private utils: Utils,
84
+ private cdRef: ChangeDetectorRef
85
+ ) {}
86
+
87
+ async ngOnInit() {
88
+ // Loading map
89
+ const apiKey = this.pConn$.getGoogleMapsAPIKey();
90
+ await this.loader.load(apiKey);
91
+ this.mapReady = true;
92
+ this.initializeGoogleServices();
93
+ this.getPlacePredictions();
94
+
95
+ this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange);
96
+ this.controlName$ = this.angularPConnect.getComponentID(this);
97
+ this.checkAndUpdate();
98
+
99
+ if (this.formGroup$) {
100
+ // add control to formGroup
101
+ this.formGroup$.addControl(this.controlName$, this.searchControl);
102
+ this.bHasForm$ = true;
103
+ } else {
104
+ this.bReadonly$ = true;
105
+ this.bHasForm$ = false;
106
+ }
107
+ }
108
+
109
+ ngOnDestroy(): void {
110
+ if (this.formGroup$) {
111
+ this.formGroup$.removeControl(this.controlName$);
112
+ }
113
+
114
+ if (this.angularPConnectData.unsubscribeFn) {
115
+ this.angularPConnectData.unsubscribeFn();
116
+ }
117
+ }
118
+
119
+ checkAndUpdate() {
120
+ const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this);
121
+ if (bUpdateSelf) {
122
+ this.updateSelf();
123
+ }
124
+ }
125
+
126
+ onStateChange() {
127
+ setTimeout(() => {
128
+ this.checkAndUpdate();
129
+ }, 0);
130
+ }
131
+
132
+ updateSelf(): void {
133
+ this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as LocationProps;
134
+ if (this.configProps$.visibility != null) {
135
+ this.bVisible$ = this.utils.getBooleanValue(this.configProps$.visibility);
136
+ }
137
+ this.onlyCoordinates = !!this.configProps$.onlyCoordinates;
138
+ this.label$ = this.configProps$.label;
139
+ this.testId = this.configProps$.testId;
140
+
141
+ this.helperText = this.configProps$.helperText || '';
142
+ this.placeholder = this.configProps$.placeholder || '';
143
+ this.showMapReadOnly$ = !!this.configProps$.showMapReadOnly;
144
+ if (this.configProps$.readOnly != null) {
145
+ this.bReadonly$ = this.utils.getBooleanValue(this.configProps$.readOnly);
146
+ }
147
+ this.showMap = this.bReadonly$ ? this.showMapReadOnly$ : !!this.configProps$.showMap;
148
+ if (this.configProps$.coordinates) {
149
+ const latAndLong: number[] = this.configProps$.coordinates.split(',').map(Number);
150
+ const latitude = Number(latAndLong[0]);
151
+ const longitude = Number(latAndLong[1]);
152
+ this.updateMap(latitude, longitude, this.configProps$.value);
153
+ }
154
+ // // timeout and detectChanges to avoid ExpressionChangedAfterItHasBeenCheckedError
155
+ setTimeout(() => {
156
+ if (this.configProps$.required != null) {
157
+ this.bRequired$ = this.utils.getBooleanValue(this.configProps$.required);
158
+ }
159
+ this.cdRef.detectChanges();
160
+ });
161
+ // // disabled
162
+ if (this.configProps$.disabled != undefined) {
163
+ this.bDisabled$ = this.utils.getBooleanValue(this.configProps$.disabled);
164
+ }
165
+
166
+ if (this.bDisabled$ || this.bReadonly$) {
167
+ this.searchControl.disable();
168
+ } else {
169
+ this.searchControl.enable();
170
+ }
171
+
172
+ this.actionsApi = this.pConn$.getActionsApi();
173
+ this.valueProp = this.pConn$.getStateProps().value;
174
+ this.coordinatesProp = this.pConn$.getStateProps().coordinates;
175
+
176
+ // // trigger display of error message with field control
177
+ if (this.angularPConnectData.validateMessage != null && this.angularPConnectData.validateMessage != '') {
178
+ const timer = interval(100).subscribe(() => {
179
+ this.searchControl.setErrors({ message: true });
180
+ this.searchControl.markAsTouched();
181
+
182
+ timer.unsubscribe();
183
+ });
184
+ }
185
+ }
186
+
187
+ onOptionSelected(event: any) {
188
+ const value = event.option.value;
189
+ if (this.isCoordinateString(value)) {
190
+ const [lat, lng] = value.split(',').map(Number);
191
+ this.updateMap(lat, lng, value);
192
+ this.updateProps();
193
+ } else {
194
+ this.geocoder.geocode({ address: value }, (res, status) => {
195
+ if (status === google.maps.GeocoderStatus.OK && res && res[0]) {
196
+ const loc = res[0].geometry.location;
197
+ this.updateMap(loc.lat(), loc.lng(), value);
198
+ this.updateProps();
199
+ }
200
+ });
201
+ }
202
+ }
203
+
204
+ fieldOnBlur() {
205
+ this.updateProps();
206
+ }
207
+
208
+ locateMe() {
209
+ if (!navigator.geolocation) {
210
+ alert('Geolocation not supported by this browser.');
211
+ return;
212
+ }
213
+
214
+ this.isLocating = true;
215
+ this.tryGetLocation(0);
216
+ }
217
+
218
+ onMapClick(event: google.maps.MapMouseEvent) {
219
+ if (!event.latLng) return;
220
+
221
+ const lat = event.latLng.lat();
222
+ const lng = event.latLng.lng();
223
+
224
+ if (this.onlyCoordinates) {
225
+ this.updateMap(lat, lng);
226
+ this.updateProps();
227
+ } else {
228
+ this.geocoder.geocode({ location: { lat, lng } }, (res, status) => {
229
+ if (status === google.maps.GeocoderStatus.OK && res && res[0]) {
230
+ this.updateMap(lat, lng, res[0].formatted_address);
231
+ } else {
232
+ this.updateMap(lat, lng);
233
+ }
234
+ this.updateProps();
235
+ });
236
+ }
237
+ }
238
+
239
+ getErrorMessage() {
240
+ let errMessage = '';
241
+
242
+ // look for validation messages for json, pre-defined or just an error pushed from workitem (400)
243
+ if (this.searchControl.hasError('message')) {
244
+ errMessage = this.angularPConnectData.validateMessage ?? '';
245
+ return errMessage;
246
+ }
247
+ if (this.searchControl.hasError('required')) {
248
+ errMessage = 'You must enter a value';
249
+ } else if (this.searchControl.errors) {
250
+ errMessage = this.searchControl.errors.toString();
251
+ }
252
+
253
+ return errMessage;
254
+ }
255
+
256
+ private tryGetLocation(retryCount: number) {
257
+ navigator.geolocation.getCurrentPosition(
258
+ position => {
259
+ const lat = position.coords.latitude;
260
+ const lng = position.coords.longitude;
261
+ if (this.onlyCoordinates) {
262
+ this.updateMap(lat, lng);
263
+ this.updateProps();
264
+ this.isLocating = false;
265
+ } else {
266
+ this.geocoder.geocode({ location: { lat, lng } }, (res, status) => {
267
+ this.isLocating = false;
268
+ if (status === google.maps.GeocoderStatus.OK && res && res[0]) {
269
+ this.updateMap(lat, lng, res[0].formatted_address);
270
+ } else {
271
+ this.updateMap(lat, lng);
272
+ }
273
+ this.updateProps();
274
+ });
275
+ }
276
+ },
277
+ err => {
278
+ console.error('Geolocation error', err);
279
+
280
+ if (err.code === err.POSITION_UNAVAILABLE && retryCount < 2) {
281
+ console.warn('Retrying location fetch...');
282
+ setTimeout(() => this.tryGetLocation(retryCount + 1), 2000);
283
+ } else {
284
+ this.isLocating = false;
285
+
286
+ switch (err.code) {
287
+ case err.PERMISSION_DENIED:
288
+ alert('Location permission denied. Please allow access in your browser settings.');
289
+ break;
290
+ case err.POSITION_UNAVAILABLE:
291
+ alert('Location unavailable. Please check your internet or GPS.');
292
+ break;
293
+ case err.TIMEOUT:
294
+ alert('Timed out while trying to get your location. Try again.');
295
+ break;
296
+ default:
297
+ alert('Could not get your location. Please try again.');
298
+ }
299
+ }
300
+ },
301
+ {
302
+ enableHighAccuracy: true,
303
+ timeout: 10000,
304
+ maximumAge: 0
305
+ }
306
+ );
307
+ }
308
+
309
+ private initializeGoogleServices() {
310
+ this.autocompleteService = new google.maps.places.AutocompleteService();
311
+ this.geocoder = new google.maps.Geocoder();
312
+ }
313
+
314
+ private getPlacePredictions() {
315
+ this.searchControl.valueChanges
316
+ .pipe(
317
+ debounceTime(300),
318
+ switchMap(value => this.getSuggestions(value || ''))
319
+ )
320
+ .subscribe(predictions => {
321
+ this.filteredOptions = predictions;
322
+ });
323
+ }
324
+
325
+ private isCoordinateString(value: string): boolean {
326
+ const regex = /^-?\d+(\.\d+)?\s*,\s*-?\d+(\.\d+)?$/;
327
+ return regex.test(value.trim());
328
+ }
329
+
330
+ private getSuggestions(input: string) {
331
+ if (!input.trim()) return of([]);
332
+
333
+ if (this.isCoordinateString(input)) {
334
+ return of([input]);
335
+ }
336
+
337
+ return from(
338
+ new Promise<string[]>(resolve => {
339
+ this.autocompleteService.getPlacePredictions({ input }, (preds, status) => {
340
+ if (status === google.maps.places.PlacesServiceStatus.OK && preds) {
341
+ if (this.onlyCoordinates) {
342
+ // only first exact match as coordinates
343
+ this.geocoder.geocode({ placeId: preds[0].place_id }, (response, geocoderStatus) => {
344
+ if (geocoderStatus === google.maps.GeocoderStatus.OK && response && response[0]) {
345
+ const loc = response[0].geometry.location;
346
+ resolve([`${loc.lat()}, ${loc.lng()}`]);
347
+ } else {
348
+ resolve([]);
349
+ }
350
+ });
351
+ } else {
352
+ resolve(preds.map(p => p.description));
353
+ }
354
+ } else {
355
+ resolve([]);
356
+ }
357
+ });
358
+ })
359
+ );
360
+ }
361
+
362
+ private updateMap(lat: number, lng: number, value?: string) {
363
+ this.center = { lat, lng };
364
+ this.markerPosition = { lat, lng };
365
+ this.setCoordinates(lat, lng);
366
+ if (this.onlyCoordinates) {
367
+ this.setLocationValue(this.coordinates);
368
+ } else {
369
+ this.setLocationValue(value || '');
370
+ }
371
+ }
372
+
373
+ private updateProps() {
374
+ handleEvent(this.actionsApi, 'change', this.valueProp, this.searchControl.value);
375
+ handleEvent(this.actionsApi, 'change', this.coordinatesProp, this.coordinates);
376
+ }
377
+
378
+ private setCoordinates(latitude: number, longitude: number) {
379
+ this.coordinates = `${latitude}, ${longitude}`;
380
+ }
381
+
382
+ private setLocationValue(value: string) {
383
+ this.searchControl.setValue(value, { emitEvent: false });
384
+ }
385
+ }
@@ -1,7 +1,7 @@
1
1
  import { CommonModule } from '@angular/common';
2
- import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
2
+ import { Component, Input, OnDestroy, OnInit } from '@angular/core';
3
3
  import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
4
- import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
4
+ import { MatAutocompleteModule } from '@angular/material/autocomplete';
5
5
  import { MatChipsModule } from '@angular/material/chips';
6
6
  import { MatCheckboxModule } from '@angular/material/checkbox';
7
7
  import { MatOptionModule } from '@angular/material/core';
@@ -9,16 +9,15 @@ import { MatFormFieldModule } from '@angular/material/form-field';
9
9
  import { MatInputModule } from '@angular/material/input';
10
10
  import { MatIconModule } from '@angular/material/icon';
11
11
  import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
12
- import { ComponentMapperComponent } from '@pega/angular-sdk-components';
13
12
  import { Utils } from '@pega/angular-sdk-components';
14
13
  import { doSearch, getDisplayFieldsMetaData, getGroupDataForItemsTree, preProcessColumns } from './utils';
15
14
  import { deleteInstruction, insertInstruction } from '@pega/angular-sdk-components';
15
+ import { handleEvent } from '@pega/angular-sdk-components';
16
16
 
17
17
  @Component({
18
18
  selector: 'app-multiselect',
19
19
  templateUrl: './multiselect.component.html',
20
20
  styleUrls: ['./multiselect.component.scss'],
21
- standalone: true,
22
21
  imports: [
23
22
  CommonModule,
24
23
  ReactiveFormsModule,
@@ -28,8 +27,7 @@ import { deleteInstruction, insertInstruction } from '@pega/angular-sdk-componen
28
27
  MatOptionModule,
29
28
  MatCheckboxModule,
30
29
  MatIconModule,
31
- MatChipsModule,
32
- forwardRef(() => ComponentMapperComponent)
30
+ MatChipsModule
33
31
  ]
34
32
  })
35
33
  export class MultiselectComponent implements OnInit, OnDestroy {
@@ -73,6 +71,8 @@ export class MultiselectComponent implements OnInit, OnDestroy {
73
71
  dataApiObj: any;
74
72
  itemsTree: any[] = [];
75
73
  trigger: any;
74
+ actionsApi: Object;
75
+ propName: string;
76
76
 
77
77
  constructor(
78
78
  private angularPConnect: AngularPConnectService,
@@ -181,7 +181,9 @@ export class MultiselectComponent implements OnInit, OnDestroy {
181
181
  listType: this.listType,
182
182
  maxResultsDisplay: this.maxResultsDisplay || '100',
183
183
  columns: preProcessColumns(columns),
184
- groupColumnsConfig: preProcessColumns(this.groupColumnsConfig)
184
+ groupColumnsConfig: preProcessColumns(this.groupColumnsConfig),
185
+ associationFilter: undefined,
186
+ ignoreCase: undefined
185
187
  };
186
188
 
187
189
  const groupsDisplayFieldMeta = this.listType !== 'associated' ? getDisplayFieldsMetaData(dataConfig.groupColumnsConfig) : null;
@@ -210,6 +212,9 @@ export class MultiselectComponent implements OnInit, OnDestroy {
210
212
  this.fieldControl.enable();
211
213
  }
212
214
 
215
+ this.actionsApi = this.pConn$.getActionsApi();
216
+ this.propName = this.pConn$.getStateProps().value;
217
+
213
218
  if (this.listType !== 'associated') {
214
219
  PCore.getDataApi()
215
220
  ?.init(dataConfig, contextName)
@@ -283,8 +288,10 @@ export class MultiselectComponent implements OnInit, OnDestroy {
283
288
  this.getCaseListBasedOnParams(this.value$, '', [...this.selectedItems], [...this.itemsTree], true);
284
289
  }
285
290
 
286
- optionChanged(event: MatAutocompleteSelectedEvent) {
287
- this.angularPConnectData.actions?.onChange(this, event);
291
+ optionChanged(event: any) {
292
+ let value = event?.target?.value;
293
+ value = value?.substring(1);
294
+ handleEvent(this.actionsApi, 'changeNblur', this.propName, value);
288
295
  }
289
296
 
290
297
  optionClicked = (event: Event, data: any): void => {
@@ -326,7 +333,7 @@ export class MultiselectComponent implements OnInit, OnDestroy {
326
333
 
327
334
  setSelectedItemsForReferenceList(data: any) {
328
335
  // Clear error messages if any
329
- const propName = (this.pConn$.getStateProps() as any).selectionList;
336
+ const propName = this.pConn$.getStateProps().selectionList;
330
337
  this.pConn$.clearErrorMessages({
331
338
  property: propName,
332
339
  category: '',
@@ -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="bHasForm$; else noEdit">
@@ -13,8 +13,8 @@
13
13
  [options]="{
14
14
  prefix: '',
15
15
  suffix: '%',
16
- thousands: currSep,
17
- decimal: currDec,
16
+ thousands: thousandSeparator,
17
+ decimal: decimalSeparator,
18
18
  align: 'left',
19
19
  nullable: true,
20
20
  precision: decimalPrecision,
@@ -11,10 +11,12 @@ import { ComponentMapperComponent } from '@pega/angular-sdk-components';
11
11
  import { handleEvent } from '@pega/angular-sdk-components';
12
12
  import { getCurrencyCharacters } from '@pega/angular-sdk-components';
13
13
  import { PConnFieldProps } from '@pega/angular-sdk-components';
14
+ import { format } from '@pega/angular-sdk-components';
14
15
 
15
16
  interface PercentageProps extends PConnFieldProps {
16
17
  showGroupSeparators?: string;
17
18
  decimalPrecision?: number;
19
+ currencyISOCode?: string;
18
20
  // If any, enter additional props that only exist on Percentage here
19
21
  }
20
22
 
@@ -22,7 +24,6 @@ interface PercentageProps extends PConnFieldProps {
22
24
  selector: 'app-percentage',
23
25
  templateUrl: './percentage.component.html',
24
26
  styleUrls: ['./percentage.component.scss'],
25
- standalone: true,
26
27
  imports: [CommonModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, NgxCurrencyDirective, forwardRef(() => ComponentMapperComponent)]
27
28
  })
28
29
  export class PercentageComponent implements OnInit, OnDestroy {
@@ -46,11 +47,14 @@ export class PercentageComponent implements OnInit, OnDestroy {
46
47
  testId: string;
47
48
  helperText: string;
48
49
  placeholder: string;
49
- currDec: string;
50
- currSep: string;
50
+ decimalSeparator: string;
51
+ thousandSeparator: string;
51
52
  inputMode: any;
52
53
  decimalPrecision: number | undefined;
53
54
  fieldControl = new FormControl<number | null>(null, null);
55
+ actionsApi: Object;
56
+ propName: string;
57
+ formattedValue: string;
54
58
 
55
59
  constructor(
56
60
  private angularPConnect: AngularPConnectService,
@@ -113,20 +117,25 @@ export class PercentageComponent implements OnInit, OnDestroy {
113
117
  this.label$ = this.configProps$.label;
114
118
  this.displayMode$ = this.configProps$.displayMode;
115
119
  this.inputMode = NgxCurrencyInputMode.Natural;
116
- let nValue: any = this.configProps$.value;
120
+ const nValue: any = this.configProps$.value;
117
121
  if (nValue) {
118
- if (typeof nValue === 'string') {
119
- nValue = parseInt(nValue, 10);
120
- }
121
122
  this.value$ = nValue;
123
+ this.fieldControl.setValue(nValue);
122
124
  }
123
125
  this.helperText = this.configProps$.helperText;
124
126
  this.placeholder = this.configProps$.placeholder || '';
125
127
  const showGroupSeparators = this.configProps$.showGroupSeparators;
126
128
 
127
129
  const theSymbols = getCurrencyCharacters('');
128
- this.currDec = theSymbols.theDecimalIndicator || '2';
129
- this.currSep = showGroupSeparators ? theSymbols.theDigitGroupSeparator : '';
130
+ this.decimalSeparator = theSymbols.theDecimalIndicator;
131
+ this.thousandSeparator = showGroupSeparators ? theSymbols.theDigitGroupSeparator : '';
132
+
133
+ this.actionsApi = this.pConn$.getActionsApi();
134
+ this.propName = this.pConn$.getStateProps().value;
135
+
136
+ if (this.displayMode$ === 'DISPLAY_ONLY' || this.displayMode$ === 'STACKED_LARGE_VAL') {
137
+ this.formattedValue = nValue ? format(nValue, 'percentage') : '';
138
+ }
130
139
 
131
140
  // timeout and detectChanges to avoid ExpressionChangedAfterItHasBeenCheckedError
132
141
  setTimeout(() => {
@@ -157,7 +166,7 @@ export class PercentageComponent implements OnInit, OnDestroy {
157
166
 
158
167
  this.decimalPrecision = this.configProps$?.decimalPrecision ?? 2;
159
168
 
160
- this.componentReference = (this.pConn$.getStateProps() as any).value;
169
+ this.componentReference = this.pConn$.getStateProps().value;
161
170
 
162
171
  // trigger display of error message with field control
163
172
  if (this.angularPConnectData.validateMessage != null && this.angularPConnectData.validateMessage != '') {
@@ -170,21 +179,36 @@ export class PercentageComponent implements OnInit, OnDestroy {
170
179
  }
171
180
 
172
181
  fieldOnChange(event: any) {
173
- this.angularPConnectData.actions?.onChange(this, event);
182
+ const oldVal = this.value$ ?? '';
183
+ const isValueChanged = event.target.value.toString() !== oldVal.toString();
184
+
185
+ if (isValueChanged) {
186
+ this.pConn$.clearErrorMessages({
187
+ property: this.propName
188
+ });
189
+ }
174
190
  }
175
191
 
176
192
  fieldOnBlur(event: any) {
177
- const actionsApi = this.pConn$?.getActionsApi();
178
- const propName = (this.pConn$?.getStateProps() as any).value;
179
- let value = event?.target?.value;
180
- value = value ? value.replace(/%/g, '') : '';
181
- if (this.currSep === ',') {
182
- value = value.replace(/,/g, '');
183
- } else {
184
- value = value?.replace(/\./g, '');
185
- value = value?.replace(/,/g, '.');
193
+ const oldVal = this.value$ ?? '';
194
+ const isValueChanged = event.target.value.toString() !== oldVal.toString();
195
+
196
+ if (isValueChanged) {
197
+ let value = event?.target?.value;
198
+ value = value ? value.replace(/%/g, '') : '';
199
+ // replacing thousand separator with empty string as not required in api call
200
+ if (this.configProps$.showGroupSeparators) {
201
+ const thousandSep = this.thousandSeparator === '.' ? '\\.' : this.thousandSeparator;
202
+ const regExp = new RegExp(String.raw`${thousandSep}`, 'g');
203
+ value = value?.replace(regExp, '');
204
+ }
205
+ // replacing decimal separator with '.'
206
+ if (this.decimalSeparator !== '.') {
207
+ const regExp = new RegExp(String.raw`${this.decimalSeparator}`, 'g');
208
+ value = value.replace(regExp, '.');
209
+ }
210
+ handleEvent(this.actionsApi, 'changeNblur', this.propName, value);
186
211
  }
187
- handleEvent(actionsApi, 'changeNblur', propName, value);
188
212
  }
189
213
 
190
214
  getErrorMessage() {
@@ -3,6 +3,6 @@
3
3
  "label": "Phone",
4
4
  "description": "Phone",
5
5
  "type": "Field",
6
- "subtype": "DATA_CAPTURE",
6
+ "subtype": "Text-Phone",
7
7
  "properties": []
8
8
  }
@@ -2,19 +2,22 @@
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 #f="ngForm" [formGroup]="formGroup$" *ngIf="bVisible$">
7
- <mat-form-field class="psdk-full-width" subscriptSizing="dynamic" [hintLabel]="helperText">
8
- <ngx-mat-intl-tel-input
7
+ <mat-form-field class="psdk-full-width" subscriptSizing="dynamic" [hintLabel]="helperText" floatLabel="always">
8
+ <mat-tel-input
9
9
  [attr.data-test-id]="testId"
10
10
  [formControl]="fieldControl"
11
- [preferredCountries]="['us']"
11
+ [preferredCountries]="preferredCountries"
12
12
  [enablePlaceholder]="true"
13
13
  [enableSearch]="true"
14
+ [placeholder]="placeholder"
15
+ [required]="bRequired$"
16
+ [disabled]="bDisabled$ || bReadonly$"
14
17
  (change)="fieldOnChange()"
15
- (blur)="fieldOnBlur($event)"
18
+ (blur)="fieldOnBlur()"
16
19
  >
17
- </ngx-mat-intl-tel-input>
20
+ </mat-tel-input>
18
21
  <mat-label>{{ label$ }}</mat-label>
19
22
  <mat-error *ngIf="fieldControl.invalid">{{ getErrorMessage() }}</mat-error>
20
23
  </mat-form-field>
@@ -24,6 +24,15 @@
24
24
  font-size: 0.7rem;
25
25
  }
26
26
 
27
+ ::ng-deep .cdk-overlay-pane {
28
+ left: 32rem !important;
29
+ top: 20rem !important;
30
+ }
31
+
32
+ ::ng-deep .mat-mdc-menu-panel {
33
+ max-width: 20rem;
34
+ }
35
+
27
36
  // ::ng-deep .iti {
28
37
  // display: block !important;
29
38
  // margin-bottom: 20px;