@pega/angular-sdk-overrides 23.1.10 → 24.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/designSystemExtension/material-case-summary/material-case-summary.component.html +7 -4
- package/lib/designSystemExtension/material-case-summary/material-case-summary.component.ts +3 -1
- package/lib/designSystemExtension/material-vertical-tabs/material-vertical-tabs.component.html +1 -1
- package/lib/designSystemExtension/operator/operator.component.ts +10 -5
- package/lib/field/auto-complete/auto-complete.component.ts +1 -1
- package/lib/field/cancel-alert/cancel-alert.component.ts +0 -2
- package/lib/field/check-box/check-box.component.html +16 -15
- package/lib/field/check-box/check-box.component.scss +14 -1
- package/lib/field/check-box/check-box.component.ts +126 -44
- package/lib/field/currency/currency.component.html +15 -6
- package/lib/field/currency/currency.component.ts +36 -18
- package/lib/field/date-time/date-time.component.html +5 -5
- package/lib/field/date-time/date-time.component.ts +15 -37
- package/lib/field/decimal/decimal.component.html +14 -4
- package/lib/field/decimal/decimal.component.ts +42 -5
- package/lib/field/dropdown/dropdown.component.ts +0 -3
- package/lib/field/group/group.component.html +1 -1
- package/lib/field/group/group.component.ts +4 -0
- package/lib/field/multiselect/multiselect.component.html +33 -0
- package/lib/field/multiselect/multiselect.component.scss +7 -0
- package/lib/field/multiselect/multiselect.component.spec.ts +21 -0
- package/lib/field/multiselect/multiselect.component.ts +359 -0
- package/lib/field/multiselect/utils.ts +209 -0
- package/lib/field/percentage/percentage.component.html +15 -4
- package/lib/field/percentage/percentage.component.ts +29 -5
- package/lib/field/radio-buttons/radio-buttons.component.ts +0 -3
- package/lib/field/rich-text/config-ext.json +10 -0
- package/lib/field/rich-text/rich-text.component.html +1 -1
- package/lib/field/scalar-list/scalar-list.component.ts +2 -1
- package/lib/field/text-area/text-area.component.ts +0 -2
- package/lib/field/time/time.component.html +1 -0
- package/lib/field/time/time.component.ts +2 -0
- package/lib/field/url/url.component.html +1 -0
- package/lib/field/url/url.component.ts +2 -0
- package/lib/field/user-reference/user-reference.component.html +50 -45
- package/lib/field/user-reference/user-reference.component.ts +33 -15
- package/lib/infra/Containers/base-components/flow-container-base.component.ts +22 -0
- package/lib/infra/Containers/base-components/helper.ts +89 -0
- package/lib/infra/Containers/flow-container/flow-container.component.html +8 -3
- package/lib/infra/Containers/flow-container/flow-container.component.ts +30 -29
- package/lib/infra/Containers/modal-view-container/modal-view-container.component.ts +40 -8
- package/lib/infra/Containers/view-container/view-container.component.ts +0 -1
- package/lib/infra/assignment/assignment.component.ts +38 -39
- package/lib/infra/dashboard-filter/dashboard-filter.component.ts +0 -1
- package/lib/infra/defer-load/defer-load.component.ts +5 -8
- package/lib/infra/multi-step/multi-step.component.html +1 -1
- package/lib/infra/multi-step/multi-step.component.scss +1 -0
- package/lib/infra/navbar/navbar.component.html +4 -4
- package/lib/infra/navbar/navbar.component.ts +6 -3
- package/lib/infra/view/view.component.ts +1 -1
- package/lib/template/banner-page/config-ext.json +9 -0
- package/lib/template/case-summary/case-summary.component.ts +37 -3
- package/lib/template/case-view/case-view.component.html +3 -3
- package/lib/template/case-view/case-view.component.scss +2 -0
- package/lib/template/case-view/case-view.component.ts +0 -6
- package/lib/template/data-reference/data-reference.component.ts +1 -3
- package/lib/template/dynamic-tabs/dynamic-tabs.component.ts +0 -1
- package/lib/template/field-group-template/field-group-template.component.ts +4 -12
- package/lib/template/field-value-list/field-value-list.component.html +7 -2
- package/lib/template/field-value-list/field-value-list.component.ts +1 -0
- package/lib/template/inline-dashboard-page/config-ext.json +9 -0
- package/lib/template/list-view/list-view.component.html +6 -6
- package/lib/template/list-view/list-view.component.ts +36 -28
- package/lib/template/list-view/listViewHelpers.ts +0 -1
- package/lib/template/repeating-structures/repeating-structures.component.ts +1 -2
- package/lib/template/simple-table/simple-table.component.ts +0 -2
- package/lib/template/simple-table-manual/helpers.ts +1 -1
- package/lib/template/simple-table-manual/simple-table-manual.component.html +1 -1
- package/lib/template/simple-table-manual/simple-table-manual.component.ts +49 -19
- package/lib/template/simple-table-select/simple-table-select.component.ts +2 -4
- package/lib/template/wss-nav-bar/wss-nav-bar.component.html +1 -1
- package/lib/template/wss-nav-bar/wss-nav-bar.component.ts +2 -1
- package/lib/widget/attachment/attachment.component.html +50 -26
- package/lib/widget/attachment/attachment.component.scss +118 -0
- package/lib/widget/attachment/attachment.component.ts +256 -501
- package/lib/widget/case-history/case-history.component.ts +1 -2
- package/lib/widget/feed-container/feed-container.component.ts +0 -4
- package/lib/widget/file-utility/file-utility.component.html +2 -2
- package/lib/widget/file-utility/file-utility.component.ts +13 -17
- package/lib/widget/list-utility/list-utility.component.html +1 -1
- package/lib/widget/quick-create/config-ext.json +9 -0
- package/lib/widget/quick-create/quick-create.component.ts +1 -1
- package/lib/widget/todo/todo.component.html +6 -5
- package/lib/widget/todo/todo.component.ts +7 -6
- package/package.json +1 -1
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
|
|
3
|
+
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
|
4
|
+
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
|
|
5
|
+
import { MatChipsModule } from '@angular/material/chips';
|
|
6
|
+
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
7
|
+
import { MatOptionModule } from '@angular/material/core';
|
|
8
|
+
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
9
|
+
import { MatInputModule } from '@angular/material/input';
|
|
10
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
11
|
+
import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
|
|
12
|
+
import { ComponentMapperComponent } from '@pega/angular-sdk-components';
|
|
13
|
+
import { Utils } from '@pega/angular-sdk-components';
|
|
14
|
+
import { doSearch, getDisplayFieldsMetaData, getGroupDataForItemsTree, preProcessColumns } from './utils';
|
|
15
|
+
import { deleteInstruction, insertInstruction } from '@pega/angular-sdk-components';
|
|
16
|
+
|
|
17
|
+
@Component({
|
|
18
|
+
selector: 'app-multiselect',
|
|
19
|
+
templateUrl: './multiselect.component.html',
|
|
20
|
+
styleUrls: ['./multiselect.component.scss'],
|
|
21
|
+
standalone: true,
|
|
22
|
+
imports: [
|
|
23
|
+
CommonModule,
|
|
24
|
+
ReactiveFormsModule,
|
|
25
|
+
MatFormFieldModule,
|
|
26
|
+
MatInputModule,
|
|
27
|
+
MatAutocompleteModule,
|
|
28
|
+
MatOptionModule,
|
|
29
|
+
MatCheckboxModule,
|
|
30
|
+
MatIconModule,
|
|
31
|
+
MatChipsModule,
|
|
32
|
+
forwardRef(() => ComponentMapperComponent)
|
|
33
|
+
]
|
|
34
|
+
})
|
|
35
|
+
export class MultiselectComponent implements OnInit, OnDestroy {
|
|
36
|
+
@Input() pConn$: typeof PConnect;
|
|
37
|
+
@Input() formGroup$: FormGroup;
|
|
38
|
+
|
|
39
|
+
// Used with AngularPConnect
|
|
40
|
+
angularPConnectData: AngularPConnectData = {};
|
|
41
|
+
|
|
42
|
+
label$ = '';
|
|
43
|
+
value$ = '';
|
|
44
|
+
bRequired$ = false;
|
|
45
|
+
bDisabled$ = false;
|
|
46
|
+
bVisible$ = true;
|
|
47
|
+
controlName$: string;
|
|
48
|
+
bHasForm$ = true;
|
|
49
|
+
listType: string;
|
|
50
|
+
placeholder: string;
|
|
51
|
+
fieldControl = new FormControl('', null);
|
|
52
|
+
parameters: {};
|
|
53
|
+
hideLabel: boolean;
|
|
54
|
+
configProps$: any;
|
|
55
|
+
|
|
56
|
+
referenceList: any;
|
|
57
|
+
selectionKey: string;
|
|
58
|
+
primaryField: string;
|
|
59
|
+
initialCaseClass: any;
|
|
60
|
+
showSecondaryInSearchOnly = false;
|
|
61
|
+
isGroupData = false;
|
|
62
|
+
referenceType;
|
|
63
|
+
secondaryFields;
|
|
64
|
+
groupDataSource = [];
|
|
65
|
+
matchPosition = 'contains';
|
|
66
|
+
maxResultsDisplay;
|
|
67
|
+
groupColumnsConfig = [{}];
|
|
68
|
+
selectionList;
|
|
69
|
+
listActions: any;
|
|
70
|
+
selectedItems: any[] = [];
|
|
71
|
+
itemsTreeBaseData = [];
|
|
72
|
+
displayFieldMeta: any;
|
|
73
|
+
dataApiObj: any;
|
|
74
|
+
itemsTree: any[] = [];
|
|
75
|
+
trigger: any;
|
|
76
|
+
|
|
77
|
+
constructor(
|
|
78
|
+
private angularPConnect: AngularPConnectService,
|
|
79
|
+
private utils: Utils
|
|
80
|
+
) {}
|
|
81
|
+
|
|
82
|
+
ngOnInit(): void {
|
|
83
|
+
// First thing in initialization is registering and subscribing to the AngularPConnect service
|
|
84
|
+
this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange);
|
|
85
|
+
this.controlName$ = this.angularPConnect.getComponentID(this);
|
|
86
|
+
|
|
87
|
+
// Then, continue on with other initialization
|
|
88
|
+
this.checkAndUpdate();
|
|
89
|
+
|
|
90
|
+
if (this.formGroup$) {
|
|
91
|
+
// add control to formGroup
|
|
92
|
+
this.formGroup$.addControl(this.controlName$, this.fieldControl);
|
|
93
|
+
this.fieldControl.setValue(this.value$);
|
|
94
|
+
this.bHasForm$ = true;
|
|
95
|
+
} else {
|
|
96
|
+
this.bHasForm$ = false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
ngOnDestroy(): void {
|
|
101
|
+
if (this.formGroup$) {
|
|
102
|
+
this.formGroup$.removeControl(this.controlName$);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (this.angularPConnectData.unsubscribeFn) {
|
|
106
|
+
this.angularPConnectData.unsubscribeFn();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Callback passed when subscribing to store change
|
|
111
|
+
onStateChange() {
|
|
112
|
+
this.checkAndUpdate();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
checkAndUpdate() {
|
|
116
|
+
// Should always check the bridge to see if the component should
|
|
117
|
+
// update itself (re-render)
|
|
118
|
+
const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this);
|
|
119
|
+
|
|
120
|
+
// ONLY call updateSelf when the component should update
|
|
121
|
+
if (bUpdateSelf) {
|
|
122
|
+
this.updateSelf();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// updateSelf
|
|
127
|
+
updateSelf() {
|
|
128
|
+
this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps());
|
|
129
|
+
|
|
130
|
+
let { datasource = [], columns = [{}] } = this.configProps$;
|
|
131
|
+
this.setPropertyValuesFromProps();
|
|
132
|
+
|
|
133
|
+
if (this.referenceList.length > 0) {
|
|
134
|
+
datasource = this.referenceList;
|
|
135
|
+
columns = [
|
|
136
|
+
{
|
|
137
|
+
value: this.primaryField,
|
|
138
|
+
display: 'true',
|
|
139
|
+
useForSearch: true,
|
|
140
|
+
primary: 'true'
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
value: this.selectionKey,
|
|
144
|
+
setProperty: this.selectionKey,
|
|
145
|
+
key: 'true'
|
|
146
|
+
}
|
|
147
|
+
];
|
|
148
|
+
let secondaryColumns: any = [];
|
|
149
|
+
if (this.secondaryFields) {
|
|
150
|
+
secondaryColumns = this.secondaryFields.map(secondaryField => ({
|
|
151
|
+
value: secondaryField,
|
|
152
|
+
display: 'true',
|
|
153
|
+
secondary: 'true',
|
|
154
|
+
useForSearch: 'true'
|
|
155
|
+
}));
|
|
156
|
+
} else {
|
|
157
|
+
secondaryColumns = [
|
|
158
|
+
{
|
|
159
|
+
value: this.selectionKey,
|
|
160
|
+
display: 'true',
|
|
161
|
+
secondary: 'true',
|
|
162
|
+
useForSearch: 'true'
|
|
163
|
+
}
|
|
164
|
+
];
|
|
165
|
+
}
|
|
166
|
+
if (this.referenceType === 'Case') {
|
|
167
|
+
columns = [...columns, ...secondaryColumns];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
this.value$ = this.value$ ? this.value$ : '';
|
|
172
|
+
const contextName = this.pConn$.getContextName();
|
|
173
|
+
|
|
174
|
+
const dataConfig = {
|
|
175
|
+
dataSource: datasource,
|
|
176
|
+
groupDataSource: this.groupDataSource,
|
|
177
|
+
isGroupData: this.isGroupData,
|
|
178
|
+
showSecondaryInSearchOnly: this.showSecondaryInSearchOnly,
|
|
179
|
+
parameters: this.parameters,
|
|
180
|
+
matchPosition: this.matchPosition,
|
|
181
|
+
listType: this.listType,
|
|
182
|
+
maxResultsDisplay: this.maxResultsDisplay || '100',
|
|
183
|
+
columns: preProcessColumns(columns),
|
|
184
|
+
groupColumnsConfig: preProcessColumns(this.groupColumnsConfig)
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const groupsDisplayFieldMeta = this.listType !== 'associated' ? getDisplayFieldsMetaData(dataConfig.groupColumnsConfig) : null;
|
|
188
|
+
|
|
189
|
+
this.itemsTreeBaseData = getGroupDataForItemsTree(this.groupDataSource, groupsDisplayFieldMeta, this.showSecondaryInSearchOnly) || [];
|
|
190
|
+
|
|
191
|
+
this.itemsTree = this.isGroupData ? getGroupDataForItemsTree(this.groupDataSource, groupsDisplayFieldMeta, this.showSecondaryInSearchOnly) : [];
|
|
192
|
+
|
|
193
|
+
this.displayFieldMeta = this.listType !== 'associated' ? getDisplayFieldsMetaData(dataConfig.columns) : null;
|
|
194
|
+
|
|
195
|
+
this.listActions = this.pConn$.getListActions();
|
|
196
|
+
this.pConn$.setReferenceList(this.selectionList);
|
|
197
|
+
|
|
198
|
+
if (this.configProps$.visibility != null) {
|
|
199
|
+
this.bVisible$ = this.utils.getBooleanValue(this.configProps$.visibility);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// disabled
|
|
203
|
+
if (this.configProps$.disabled != undefined) {
|
|
204
|
+
this.bDisabled$ = this.utils.getBooleanValue(this.configProps$.disabled);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (this.bDisabled$) {
|
|
208
|
+
this.fieldControl.disable();
|
|
209
|
+
} else {
|
|
210
|
+
this.fieldControl.enable();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (this.listType !== 'associated') {
|
|
214
|
+
PCore.getDataApi()
|
|
215
|
+
?.init(dataConfig, contextName)
|
|
216
|
+
.then(async dataObj => {
|
|
217
|
+
this.dataApiObj = dataObj;
|
|
218
|
+
if (!this.isGroupData) {
|
|
219
|
+
this.getCaseListBasedOnParams(this.value$ ?? '', '', [...this.selectedItems], [...this.itemsTree]);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
setPropertyValuesFromProps() {
|
|
226
|
+
this.label$ = this.configProps$.label;
|
|
227
|
+
this.placeholder = this.configProps$.placeholder || '';
|
|
228
|
+
this.listType = this.configProps$.listType ? this.configProps$.listType : '';
|
|
229
|
+
this.hideLabel = this.configProps$.hideLabel;
|
|
230
|
+
this.parameters = this.configProps$?.parameters ? this.configProps$?.parameters : {};
|
|
231
|
+
this.referenceList = this.configProps$?.referenceList;
|
|
232
|
+
this.selectionKey = this.configProps$?.selectionKey;
|
|
233
|
+
this.primaryField = this.configProps$?.primaryField;
|
|
234
|
+
this.initialCaseClass = this.configProps$?.initialCaseClass;
|
|
235
|
+
this.showSecondaryInSearchOnly = this.configProps$?.showSecondaryInSearchOnly ? this.configProps$?.showSecondaryInSearchOnly : false;
|
|
236
|
+
this.isGroupData = this.configProps$?.isGroupData ? this.configProps$.isGroupData : false;
|
|
237
|
+
this.referenceType = this.configProps$?.referenceType;
|
|
238
|
+
this.secondaryFields = this.configProps$?.secondaryFields;
|
|
239
|
+
this.groupDataSource = this.configProps$?.groupDataSource ? this.configProps$?.groupDataSource : [];
|
|
240
|
+
this.matchPosition = this.configProps$?.matchPosition ? this.configProps$?.matchPosition : 'contains';
|
|
241
|
+
this.maxResultsDisplay = this.configProps$?.maxResultsDisplay;
|
|
242
|
+
this.groupColumnsConfig = this.configProps$?.groupColumnsConfig ? this.configProps$?.groupColumnsConfig : [{}];
|
|
243
|
+
this.selectionList = this.configProps$?.selectionList;
|
|
244
|
+
this.value$ = this.configProps$?.value;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// main search function trigger
|
|
248
|
+
getCaseListBasedOnParams(searchText, group, selectedRows, currentItemsTree, isTriggeredFromSearch = false) {
|
|
249
|
+
if (this.referenceList && this.referenceList.length > 0) {
|
|
250
|
+
this.listActions.getSelectedRows(true).then(result => {
|
|
251
|
+
selectedRows =
|
|
252
|
+
result.length > 0
|
|
253
|
+
? result.map(item => {
|
|
254
|
+
return {
|
|
255
|
+
id: item[this.selectionKey.startsWith('.') ? this.selectionKey.substring(1) : this.selectionKey],
|
|
256
|
+
primary: item[this.primaryField.startsWith('.') ? this.primaryField.substring(1) : this.primaryField]
|
|
257
|
+
};
|
|
258
|
+
})
|
|
259
|
+
: [];
|
|
260
|
+
this.selectedItems = selectedRows;
|
|
261
|
+
|
|
262
|
+
const initalItemsTree = isTriggeredFromSearch || !currentItemsTree ? [...this.itemsTreeBaseData] : [...currentItemsTree];
|
|
263
|
+
|
|
264
|
+
doSearch(
|
|
265
|
+
searchText,
|
|
266
|
+
group,
|
|
267
|
+
this.initialCaseClass,
|
|
268
|
+
this.displayFieldMeta,
|
|
269
|
+
this.dataApiObj,
|
|
270
|
+
initalItemsTree,
|
|
271
|
+
this.isGroupData,
|
|
272
|
+
this.showSecondaryInSearchOnly,
|
|
273
|
+
selectedRows || []
|
|
274
|
+
).then(res => {
|
|
275
|
+
this.itemsTree = res || [];
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
fieldOnChange(event: Event) {
|
|
282
|
+
this.value$ = (event.target as HTMLInputElement).value;
|
|
283
|
+
this.getCaseListBasedOnParams(this.value$, '', [...this.selectedItems], [...this.itemsTree], true);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
optionChanged(event: MatAutocompleteSelectedEvent) {
|
|
287
|
+
this.angularPConnectData.actions?.onChange(this, event);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
optionClicked = (event: Event, data: any): void => {
|
|
291
|
+
event.stopPropagation();
|
|
292
|
+
this.toggleSelection(data);
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
toggleSelection = (data: any): void => {
|
|
296
|
+
data.selected = !data.selected;
|
|
297
|
+
this.itemsTree.map((ele: any) => {
|
|
298
|
+
if (ele.id === data.id) {
|
|
299
|
+
ele.selected = data.selected;
|
|
300
|
+
}
|
|
301
|
+
return ele;
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
if (data.selected === true) {
|
|
305
|
+
this.selectedItems.push(data);
|
|
306
|
+
} else {
|
|
307
|
+
const index = this.selectedItems.findIndex(value => value.id === data.id);
|
|
308
|
+
this.selectedItems.splice(index, 1);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
this.value$ = '';
|
|
312
|
+
// if this is a referenceList case
|
|
313
|
+
if (this.referenceList) this.setSelectedItemsForReferenceList(data);
|
|
314
|
+
|
|
315
|
+
this.getCaseListBasedOnParams(this.value$, '', [...this.selectedItems], [...this.itemsTree], true);
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
removeChip = (data: any): void => {
|
|
319
|
+
if (data) {
|
|
320
|
+
data = this.itemsTree.filter((ele: any) => {
|
|
321
|
+
return ele.id === data.id;
|
|
322
|
+
});
|
|
323
|
+
this.toggleSelection(data[0]);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
setSelectedItemsForReferenceList(data: any) {
|
|
328
|
+
// Clear error messages if any
|
|
329
|
+
const propName = (this.pConn$.getStateProps() as any).selectionList;
|
|
330
|
+
this.pConn$.clearErrorMessages({
|
|
331
|
+
property: propName,
|
|
332
|
+
category: '',
|
|
333
|
+
context: ''
|
|
334
|
+
});
|
|
335
|
+
const { selected } = data;
|
|
336
|
+
if (selected) {
|
|
337
|
+
insertInstruction(this.pConn$, this.selectionList, this.selectionKey, this.primaryField, data);
|
|
338
|
+
} else {
|
|
339
|
+
deleteInstruction(this.pConn$, this.selectionList, this.selectionKey, data);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
getErrorMessage() {
|
|
344
|
+
let errMessage = '';
|
|
345
|
+
|
|
346
|
+
// look for validation messages for json, pre-defined or just an error pushed from workitem (400)
|
|
347
|
+
if (this.fieldControl.hasError('message')) {
|
|
348
|
+
errMessage = this.angularPConnectData.validateMessage ?? '';
|
|
349
|
+
return errMessage;
|
|
350
|
+
}
|
|
351
|
+
if (this.fieldControl.hasError('required')) {
|
|
352
|
+
errMessage = 'You must enter a value';
|
|
353
|
+
} else if (this.fieldControl.errors) {
|
|
354
|
+
errMessage = this.fieldControl.errors.toString();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return errMessage;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import cloneDeep from 'lodash.clonedeep';
|
|
2
|
+
|
|
3
|
+
export function setVisibilityForList(c11nEnv, visibility) {
|
|
4
|
+
const { selectionMode, selectionList, renderMode, referenceList } = c11nEnv.getComponentConfig();
|
|
5
|
+
// usecase:multiselect, fieldgroup, editable table
|
|
6
|
+
if ((selectionMode === PCore.getConstants().LIST_SELECTION_MODE.MULTI && selectionList) || (renderMode === 'Editable' && referenceList)) {
|
|
7
|
+
c11nEnv.getListActions().setVisibility(visibility);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function preProcessColumns(columns) {
|
|
12
|
+
return columns?.map(col => {
|
|
13
|
+
const tempColObj = { ...col };
|
|
14
|
+
tempColObj.value = col.value && col.value.startsWith('.') ? col.value.substring(1) : col.value;
|
|
15
|
+
if (tempColObj.setProperty) {
|
|
16
|
+
tempColObj.setProperty = col.setProperty && col.setProperty.startsWith('.') ? col.setProperty.substring(1) : col.setProperty;
|
|
17
|
+
}
|
|
18
|
+
return tempColObj;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getDisplayFieldsMetaData(columns) {
|
|
23
|
+
const displayColumns = columns?.filter(col => col.display === 'true');
|
|
24
|
+
const metaDataObj: any = {
|
|
25
|
+
key: '',
|
|
26
|
+
primary: '',
|
|
27
|
+
secondary: []
|
|
28
|
+
};
|
|
29
|
+
const keyCol = columns?.filter(col => col.key === 'true');
|
|
30
|
+
metaDataObj.key = keyCol?.length > 0 ? keyCol[0].value : 'auto';
|
|
31
|
+
const itemsRecordsColumn = columns?.filter(col => col.itemsRecordsColumn === 'true');
|
|
32
|
+
if (itemsRecordsColumn?.length > 0) {
|
|
33
|
+
metaDataObj.itemsRecordsColumn = itemsRecordsColumn[0].value;
|
|
34
|
+
}
|
|
35
|
+
const itemsGroupKeyColumn = columns?.filter(col => col.itemsGroupKeyColumn === 'true');
|
|
36
|
+
if (itemsGroupKeyColumn?.length > 0) {
|
|
37
|
+
metaDataObj.itemsGroupKeyColumn = itemsGroupKeyColumn[0].value;
|
|
38
|
+
}
|
|
39
|
+
for (let index = 0; index < displayColumns?.length; index += 1) {
|
|
40
|
+
if (displayColumns[index].secondary === 'true') {
|
|
41
|
+
metaDataObj.secondary.push(displayColumns[index].value);
|
|
42
|
+
} else if (displayColumns[index].primary === 'true') {
|
|
43
|
+
metaDataObj.primary = displayColumns[index].value;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return metaDataObj;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function createSingleTreeObejct(entry, displayFieldMeta, showSecondaryData, selected) {
|
|
50
|
+
const secondaryArr: any = [];
|
|
51
|
+
displayFieldMeta.secondary.forEach(col => {
|
|
52
|
+
secondaryArr.push(entry[col]);
|
|
53
|
+
});
|
|
54
|
+
const isSelected = selected.some(item => item.id === entry[displayFieldMeta.key]);
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
id: entry[displayFieldMeta.key],
|
|
58
|
+
primary: entry[displayFieldMeta.primary],
|
|
59
|
+
secondary: showSecondaryData ? secondaryArr : [],
|
|
60
|
+
selected: isSelected
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function putItemsDataInItemsTree(listObjData, displayFieldMeta, itemsTree, showSecondaryInSearchOnly, selected) {
|
|
65
|
+
let newTreeItems = itemsTree.slice();
|
|
66
|
+
const showSecondaryData = !showSecondaryInSearchOnly;
|
|
67
|
+
for (const obj of listObjData) {
|
|
68
|
+
const items = obj[displayFieldMeta.itemsRecordsColumn].map(entry => createSingleTreeObejct(entry, displayFieldMeta, showSecondaryData, selected));
|
|
69
|
+
|
|
70
|
+
newTreeItems = newTreeItems.map(caseObject => {
|
|
71
|
+
if (caseObject.id === obj[displayFieldMeta.itemsGroupKeyColumn]) {
|
|
72
|
+
caseObject.items = [...items];
|
|
73
|
+
}
|
|
74
|
+
return caseObject;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return newTreeItems;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function prepareSearchResults(listObjData, displayFieldMeta) {
|
|
81
|
+
const searchResults: any = [];
|
|
82
|
+
for (const obj of listObjData) {
|
|
83
|
+
searchResults.push(...obj[displayFieldMeta.itemsRecordsColumn]);
|
|
84
|
+
}
|
|
85
|
+
return searchResults;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function doSearch(
|
|
89
|
+
searchText,
|
|
90
|
+
clickedGroup,
|
|
91
|
+
initialCaseClass,
|
|
92
|
+
displayFieldMeta,
|
|
93
|
+
dataApiObj, // deep clone of the dataApiObj
|
|
94
|
+
itemsTree,
|
|
95
|
+
isGroupData,
|
|
96
|
+
showSecondaryInSearchOnly,
|
|
97
|
+
selected
|
|
98
|
+
) {
|
|
99
|
+
let searchTextForUngroupedData = '';
|
|
100
|
+
if (dataApiObj) {
|
|
101
|
+
// creating dataApiObject in grouped data cases
|
|
102
|
+
if (isGroupData) {
|
|
103
|
+
dataApiObj = cloneDeep(dataApiObj);
|
|
104
|
+
dataApiObj.fetchedNQData = false;
|
|
105
|
+
dataApiObj.cache = {};
|
|
106
|
+
|
|
107
|
+
// if we have no search text and no group selected, return the original tree
|
|
108
|
+
if (searchText === '' && clickedGroup === '') {
|
|
109
|
+
return itemsTree;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// setting the inital search text & search classes in ApiObject
|
|
113
|
+
dataApiObj.parameters[Object.keys(dataApiObj.parameters)[1]] = searchText;
|
|
114
|
+
dataApiObj.parameters[Object.keys(dataApiObj.parameters)[0]] = initialCaseClass;
|
|
115
|
+
|
|
116
|
+
// if we have a selected group
|
|
117
|
+
if (clickedGroup) {
|
|
118
|
+
// check if the data for this group is already present and no search text
|
|
119
|
+
if (searchText === '') {
|
|
120
|
+
const containsData = itemsTree.find(item => item.id === clickedGroup);
|
|
121
|
+
// do not make API call when items of respective group are already fetched
|
|
122
|
+
if (containsData?.items?.length) return itemsTree;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
dataApiObj.parameters[Object.keys(dataApiObj.parameters)[0]] = JSON.stringify([clickedGroup]);
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
searchTextForUngroupedData = searchText;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// search API call
|
|
132
|
+
const response = await dataApiObj.fetchData(searchTextForUngroupedData).catch(() => {
|
|
133
|
+
return itemsTree;
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
let listObjData = response.data;
|
|
137
|
+
let newItemsTree = [];
|
|
138
|
+
if (isGroupData) {
|
|
139
|
+
if (searchText) {
|
|
140
|
+
listObjData = prepareSearchResults(listObjData, displayFieldMeta);
|
|
141
|
+
} else {
|
|
142
|
+
newItemsTree = putItemsDataInItemsTree(listObjData, displayFieldMeta, itemsTree, showSecondaryInSearchOnly, selected);
|
|
143
|
+
return newItemsTree;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const showSecondaryData = showSecondaryInSearchOnly ? !!searchText : true;
|
|
147
|
+
if (listObjData !== undefined && listObjData.length > 0) {
|
|
148
|
+
newItemsTree = listObjData.map(entry => createSingleTreeObejct(entry, displayFieldMeta, showSecondaryData, selected));
|
|
149
|
+
}
|
|
150
|
+
return newItemsTree;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return itemsTree;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function setValuesToPropertyList(searchText, assocProp, items, columns, actions, updatePropertyInRedux = true) {
|
|
157
|
+
const setPropertyList = columns
|
|
158
|
+
?.filter(col => col.setProperty)
|
|
159
|
+
.map(col => {
|
|
160
|
+
return {
|
|
161
|
+
source: col.value,
|
|
162
|
+
target: col.setProperty,
|
|
163
|
+
key: col.key,
|
|
164
|
+
primary: col.primary
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
const valueToSet: any = [];
|
|
168
|
+
if (setPropertyList.length > 0) {
|
|
169
|
+
setPropertyList.forEach(prop => {
|
|
170
|
+
items.forEach(item => {
|
|
171
|
+
if (prop.key === 'true' && item) {
|
|
172
|
+
valueToSet.push(item.id);
|
|
173
|
+
} else if (prop.primary === 'true' || !item) {
|
|
174
|
+
valueToSet.push(searchText);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
if (updatePropertyInRedux) {
|
|
179
|
+
// BUG-666851 setting options so that the store values are replaced and not merged
|
|
180
|
+
const options = {
|
|
181
|
+
isArrayDeepMerge: false
|
|
182
|
+
};
|
|
183
|
+
if (prop.target === 'Associated property') {
|
|
184
|
+
actions.updateFieldValue(assocProp, valueToSet, options);
|
|
185
|
+
} else {
|
|
186
|
+
actions.updateFieldValue(`.${prop.target}`, valueToSet, options);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return valueToSet;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function getGroupDataForItemsTree(groupDataSource, groupsDisplayFieldMeta, showSecondaryInSearchOnly) {
|
|
195
|
+
return groupDataSource?.map(group => {
|
|
196
|
+
const secondaryArr: any = [];
|
|
197
|
+
groupsDisplayFieldMeta.secondary.forEach(col => {
|
|
198
|
+
secondaryArr.push(group[col]);
|
|
199
|
+
});
|
|
200
|
+
return {
|
|
201
|
+
id: group[groupsDisplayFieldMeta.key],
|
|
202
|
+
primary: group[groupsDisplayFieldMeta.primary],
|
|
203
|
+
secondary: showSecondaryInSearchOnly ? [] : secondaryArr,
|
|
204
|
+
items: []
|
|
205
|
+
};
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export { preProcessColumns, getDisplayFieldsMetaData, doSearch, setValuesToPropertyList, getGroupDataForItemsTree };
|
|
@@ -2,22 +2,33 @@
|
|
|
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="
|
|
5
|
+
<div *ngIf="bHasForm$; else noEdit">
|
|
6
6
|
<div [formGroup]="formGroup$" *ngIf="bVisible$">
|
|
7
7
|
<mat-form-field class="psdk-full-width" subscriptSizing="dynamic" [hintLabel]="helperText">
|
|
8
8
|
<mat-label>{{ label$ }}</mat-label>
|
|
9
|
-
<!-- <span matPrefix>% </span> -->
|
|
10
9
|
<input
|
|
10
|
+
type="text"
|
|
11
11
|
matInput
|
|
12
|
+
currencyMask
|
|
13
|
+
[options]="{
|
|
14
|
+
prefix: '',
|
|
15
|
+
suffix: '%',
|
|
16
|
+
thousands: currSep,
|
|
17
|
+
decimal: currDec,
|
|
18
|
+
align: 'left',
|
|
19
|
+
nullable: true,
|
|
20
|
+
precision: decimalPrecision,
|
|
21
|
+
inputMode: inputMode
|
|
22
|
+
}"
|
|
12
23
|
[placeholder]="placeholder"
|
|
13
|
-
type="number"
|
|
14
24
|
step=".01"
|
|
15
|
-
[
|
|
25
|
+
[formControlName]="controlName$"
|
|
16
26
|
[required]="bRequired$"
|
|
17
27
|
[formControl]="fieldControl"
|
|
18
28
|
[attr.data-test-id]="testId"
|
|
19
29
|
(change)="fieldOnChange($event)"
|
|
20
30
|
(blur)="fieldOnBlur($event)"
|
|
31
|
+
[readonly]="bReadonly$"
|
|
21
32
|
/>
|
|
22
33
|
<mat-error *ngIf="fieldControl.invalid">{{ getErrorMessage() }}</mat-error>
|
|
23
34
|
</mat-form-field>
|
|
@@ -4,12 +4,17 @@ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
|
|
4
4
|
import { MatInputModule } from '@angular/material/input';
|
|
5
5
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
6
6
|
import { interval } from 'rxjs';
|
|
7
|
+
import { NgxCurrencyDirective, NgxCurrencyInputMode } from 'ngx-currency';
|
|
7
8
|
import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
|
|
8
9
|
import { Utils } from '@pega/angular-sdk-components';
|
|
9
10
|
import { ComponentMapperComponent } from '@pega/angular-sdk-components';
|
|
11
|
+
import { handleEvent } from '@pega/angular-sdk-components';
|
|
12
|
+
import { getCurrencyCharacters } from '@pega/angular-sdk-components';
|
|
10
13
|
import { PConnFieldProps } from '@pega/angular-sdk-components';
|
|
11
14
|
|
|
12
15
|
interface PercentageProps extends PConnFieldProps {
|
|
16
|
+
showGroupSeparators?: string;
|
|
17
|
+
decimalPrecision?: number;
|
|
13
18
|
// If any, enter additional props that only exist on Percentage here
|
|
14
19
|
}
|
|
15
20
|
|
|
@@ -18,7 +23,7 @@ interface PercentageProps extends PConnFieldProps {
|
|
|
18
23
|
templateUrl: './percentage.component.html',
|
|
19
24
|
styleUrls: ['./percentage.component.scss'],
|
|
20
25
|
standalone: true,
|
|
21
|
-
imports: [CommonModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, forwardRef(() => ComponentMapperComponent)]
|
|
26
|
+
imports: [CommonModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, NgxCurrencyDirective, forwardRef(() => ComponentMapperComponent)]
|
|
22
27
|
})
|
|
23
28
|
export class PercentageComponent implements OnInit, OnDestroy {
|
|
24
29
|
@Input() pConn$: typeof PConnect;
|
|
@@ -41,7 +46,10 @@ export class PercentageComponent implements OnInit, OnDestroy {
|
|
|
41
46
|
testId: string;
|
|
42
47
|
helperText: string;
|
|
43
48
|
placeholder: string;
|
|
44
|
-
|
|
49
|
+
currDec: string;
|
|
50
|
+
currSep: string;
|
|
51
|
+
inputMode: any;
|
|
52
|
+
decimalPrecision: number | undefined;
|
|
45
53
|
fieldControl = new FormControl<number | null>(null, null);
|
|
46
54
|
|
|
47
55
|
constructor(
|
|
@@ -104,6 +112,7 @@ export class PercentageComponent implements OnInit, OnDestroy {
|
|
|
104
112
|
this.testId = this.configProps$.testId;
|
|
105
113
|
this.label$ = this.configProps$.label;
|
|
106
114
|
this.displayMode$ = this.configProps$.displayMode;
|
|
115
|
+
this.inputMode = NgxCurrencyInputMode.Natural;
|
|
107
116
|
let nValue: any = this.configProps$.value;
|
|
108
117
|
if (nValue) {
|
|
109
118
|
if (typeof nValue === 'string') {
|
|
@@ -113,6 +122,11 @@ export class PercentageComponent implements OnInit, OnDestroy {
|
|
|
113
122
|
}
|
|
114
123
|
this.helperText = this.configProps$.helperText;
|
|
115
124
|
this.placeholder = this.configProps$.placeholder || '';
|
|
125
|
+
const showGroupSeparators = this.configProps$.showGroupSeparators;
|
|
126
|
+
|
|
127
|
+
const theSymbols = getCurrencyCharacters('');
|
|
128
|
+
this.currDec = theSymbols.theDecimalIndicator || '2';
|
|
129
|
+
this.currSep = showGroupSeparators ? theSymbols.theDigitGroupSeparator : '';
|
|
116
130
|
|
|
117
131
|
// timeout and detectChanges to avoid ExpressionChangedAfterItHasBeenCheckedError
|
|
118
132
|
setTimeout(() => {
|
|
@@ -141,6 +155,8 @@ export class PercentageComponent implements OnInit, OnDestroy {
|
|
|
141
155
|
this.bReadonly$ = this.utils.getBooleanValue(this.configProps$.readOnly);
|
|
142
156
|
}
|
|
143
157
|
|
|
158
|
+
this.decimalPrecision = this.configProps$?.decimalPrecision ?? 2;
|
|
159
|
+
|
|
144
160
|
this.componentReference = (this.pConn$.getStateProps() as any).value;
|
|
145
161
|
|
|
146
162
|
// trigger display of error message with field control
|
|
@@ -158,9 +174,17 @@ export class PercentageComponent implements OnInit, OnDestroy {
|
|
|
158
174
|
}
|
|
159
175
|
|
|
160
176
|
fieldOnBlur(event: any) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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, '.');
|
|
186
|
+
}
|
|
187
|
+
handleEvent(actionsApi, 'changeNblur', propName, value);
|
|
164
188
|
}
|
|
165
189
|
|
|
166
190
|
getErrorMessage() {
|