@pega/angular-sdk-overrides 0.26.2 → 0.26.4
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/field-group/field-group.component.ts +11 -3
- package/lib/designSystemExtension/material-case-summary/material-case-summary.component.html +12 -3
- package/lib/field/auto-complete/auto-complete.component.html +44 -4
- package/lib/field/auto-complete/auto-complete.component.scss +92 -0
- package/lib/field/auto-complete/auto-complete.component.ts +341 -16
- package/lib/field/cancel-alert/cancel-alert.component.ts +38 -15
- package/lib/field/group/group.component.html +1 -1
- package/lib/field/group/group.component.ts +1 -3
- package/lib/field/semantic-link/semantic-link.component.html +1 -1
- package/lib/field/semantic-link/semantic-link.component.scss +4 -0
- package/lib/infra/Containers/flow-container/flow-container.component.html +1 -1
- package/lib/infra/Containers/modal-view-container/data-view-action-buttons/data-view-action-buttons.component.html +12 -0
- package/lib/infra/Containers/modal-view-container/data-view-action-buttons/data-view-action-buttons.component.spec.ts +130 -0
- package/lib/infra/Containers/modal-view-container/data-view-action-buttons/data-view-action-buttons.component.ts +77 -0
- package/lib/infra/Containers/modal-view-container/modal-view-container.component.html +35 -8
- package/lib/infra/Containers/modal-view-container/modal-view-container.component.ts +179 -184
- package/lib/infra/assignment/assignment.component.html +2 -1
- package/lib/infra/assignment/assignment.component.ts +30 -13
- package/lib/infra/defer-load/defer-load.component.ts +6 -3
- package/lib/infra/multi-step/multi-step.component.html +25 -33
- package/lib/infra/multi-step/multi-step.component.scss +48 -0
- package/lib/infra/multi-step/multi-step.component.ts +11 -0
- package/lib/infra/view/view.component.ts +17 -39
- package/lib/template/base/details-template-base.ts +35 -54
- package/lib/template/case-summary/case-summary.component.ts +15 -1
- package/lib/template/case-view/case-view.component.html +13 -1
- package/lib/template/case-view/case-view.component.spec.ts +119 -10
- package/lib/template/case-view/case-view.component.ts +52 -3
- package/lib/template/data-reference/data-reference.component.ts +27 -18
- package/lib/template/data-reference/search-form/search-form.component.html +1 -1
- package/lib/template/data-reference/search-form/search-form.component.ts +2 -0
- package/lib/template/details/details.component.html +23 -3
- package/lib/template/details/details.component.scss +9 -2
- package/lib/template/details/details.component.ts +3 -32
- package/lib/template/details-narrow-wide/details-narrow-wide.component.html +21 -2
- package/lib/template/details-narrow-wide/details-narrow-wide.component.scss +8 -1
- package/lib/template/details-narrow-wide/details-narrow-wide.component.ts +3 -37
- package/lib/template/details-one-column/details-one-column.component.html +23 -1
- package/lib/template/details-one-column/details-one-column.component.scss +14 -0
- package/lib/template/details-one-column/details-one-column.component.ts +3 -38
- package/lib/template/details-three-column/details-three-column.component.html +21 -2
- package/lib/template/details-three-column/details-three-column.component.scss +8 -1
- package/lib/template/details-three-column/details-three-column.component.ts +3 -46
- package/lib/template/details-two-column/details-two-column.component.html +21 -2
- package/lib/template/details-two-column/details-two-column.component.scss +8 -1
- package/lib/template/details-two-column/details-two-column.component.ts +3 -44
- package/lib/template/details-wide-narrow/details-wide-narrow.component.html +21 -2
- package/lib/template/details-wide-narrow/details-wide-narrow.component.scss +8 -1
- package/lib/template/details-wide-narrow/details-wide-narrow.component.ts +3 -41
- package/lib/template/field-value-list/field-value-list.component.scss +17 -0
- package/lib/template/list-view/list-view.component.ts +39 -0
- package/lib/template/self-service-case-view/self-service-case-view.component.html +13 -1
- package/lib/template/self-service-case-view/self-service-case-view.component.spec.ts +96 -11
- package/lib/template/self-service-case-view/self-service-case-view.component.ts +52 -3
- package/lib/template/simple-table-manual/helpers.ts +27 -6
- package/lib/template/simple-table-manual/simple-table-manual.component.html +1 -3
- package/lib/template/simple-table-manual/simple-table-manual.component.scss +4 -0
- package/lib/template/simple-table-manual/simple-table-manual.component.ts +51 -20
- package/lib/template/single-reference-readonly/single-reference-readonly.component.scss +0 -4
- package/package.json +1 -1
- package/lib/designSystemExtension/material-details/material-details.component.html +0 -40
- package/lib/designSystemExtension/material-details/material-details.component.scss +0 -116
- package/lib/designSystemExtension/material-details/material-details.component.spec.ts +0 -24
- package/lib/designSystemExtension/material-details/material-details.component.ts +0 -31
- package/lib/designSystemExtension/material-details-fields/material-details-fields.component.html +0 -50
- package/lib/designSystemExtension/material-details-fields/material-details-fields.component.scss +0 -34
- package/lib/designSystemExtension/material-details-fields/material-details-fields.component.spec.ts +0 -22
- package/lib/designSystemExtension/material-details-fields/material-details-fields.component.ts +0 -61
|
@@ -1,43 +1,35 @@
|
|
|
1
1
|
<div *ngIf="bShow$">
|
|
2
|
-
<div
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<div class="
|
|
11
|
-
{{ mainStep.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<div class="{{ _getVBodyClass(i) }}">
|
|
15
|
-
<ng-container *ngIf="mainStep?.steps && mainStep.visited_status == 'current'">
|
|
16
|
-
<div *ngFor="let subStep of mainStep.steps">
|
|
17
|
-
<div *ngIf="subStep.visited_status == 'current'">
|
|
18
|
-
<component-mapper
|
|
19
|
-
name="AssignmentCard"
|
|
20
|
-
[props]="{ pConn$, formGroup$, arChildren$, arMainButtons$, arSecondaryButtons$ }"
|
|
21
|
-
[parent]="this"
|
|
22
|
-
[outputEvents]="{ actionButtonClick: onActionButtonClick }"
|
|
23
|
-
></component-mapper>
|
|
2
|
+
<div
|
|
3
|
+
*ngIf="isVerticalLayout()"
|
|
4
|
+
class="psdk-vertical-stepper-container"
|
|
5
|
+
[class.stepper-start]="stepIndicator$ === 'vertical-start'"
|
|
6
|
+
[class.stepper-end]="stepIndicator$ === 'vertical'"
|
|
7
|
+
>
|
|
8
|
+
<div class="psdk-stepper-rail">
|
|
9
|
+
<div *ngFor="let mainStep of arNavigationSteps$; let i = index" class="psdk-vertical-step">
|
|
10
|
+
<div class="psdk-vertical-step-header">
|
|
11
|
+
<div class="{{ _getVIconClass(mainStep.visited_status) }}">
|
|
12
|
+
<div class="psdk-vertical-step-icon-content">
|
|
13
|
+
<span>{{ i + 1 }}</span>
|
|
24
14
|
</div>
|
|
25
15
|
</div>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
name="AssignmentCard"
|
|
31
|
-
[props]="{ pConn$, formGroup$, arChildren$, arMainButtons$, arSecondaryButtons$ }"
|
|
32
|
-
[parent]="this"
|
|
33
|
-
[outputEvents]="{ actionButtonClick: onActionButtonClick }"
|
|
34
|
-
></component-mapper>
|
|
35
|
-
</ng-container>
|
|
16
|
+
<div class="{{ _getVLabelClass(mainStep.visited_status) }}">
|
|
17
|
+
{{ mainStep.name }}
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
36
20
|
</div>
|
|
37
21
|
</div>
|
|
22
|
+
<div class="psdk-stepper-content">
|
|
23
|
+
<component-mapper
|
|
24
|
+
name="AssignmentCard"
|
|
25
|
+
[props]="{ pConn$, formGroup$, arChildren$, arMainButtons$, arSecondaryButtons$ }"
|
|
26
|
+
[parent]="this"
|
|
27
|
+
[outputEvents]="{ actionButtonClick: onActionButtonClick }"
|
|
28
|
+
></component-mapper>
|
|
29
|
+
</div>
|
|
38
30
|
</div>
|
|
39
31
|
|
|
40
|
-
<div *ngIf="
|
|
32
|
+
<div *ngIf="isHorizontalLayout()" class="psdk-horizontal-stepper">
|
|
41
33
|
<div class="psdk-horizontal-stepper-header-container">
|
|
42
34
|
<ng-container *ngFor="let mainStep of arNavigationSteps$; let i = index">
|
|
43
35
|
<div class="psdk-horizontal-step-header">
|
|
@@ -143,6 +143,54 @@ mat-horizontal-stepper {
|
|
|
143
143
|
bottom: -16px;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
.psdk-vertical-stepper-container {
|
|
147
|
+
display: grid;
|
|
148
|
+
gap: 2rem;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.psdk-vertical-stepper-container.stepper-end {
|
|
152
|
+
grid-template-columns: 1fr minmax(12rem, auto);
|
|
153
|
+
grid-template-areas: 'content stepper';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.psdk-vertical-stepper-container.stepper-start {
|
|
157
|
+
grid-template-columns: minmax(12rem, auto) 1fr;
|
|
158
|
+
grid-template-areas: 'stepper content';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.psdk-stepper-rail {
|
|
162
|
+
grid-area: stepper;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.psdk-stepper-content {
|
|
166
|
+
grid-area: content;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.psdk-stepper-rail .psdk-vertical-step {
|
|
170
|
+
position: relative;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.psdk-stepper-rail .psdk-vertical-step-header {
|
|
174
|
+
height: auto;
|
|
175
|
+
overflow: visible;
|
|
176
|
+
padding: 0.75rem 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.psdk-stepper-rail .psdk-vertical-step:not(:last-child)::after {
|
|
180
|
+
content: '';
|
|
181
|
+
position: absolute;
|
|
182
|
+
left: 0.75rem;
|
|
183
|
+
top: calc(0.75rem + 1.75rem);
|
|
184
|
+
bottom: -0.25rem;
|
|
185
|
+
width: 0.0625rem;
|
|
186
|
+
background-color: var(--mat-sys-outline-variant);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.psdk-stepper-rail .psdk-vertical-step-label,
|
|
190
|
+
.psdk-stepper-rail .psdk-vertical-step-label-selected {
|
|
191
|
+
font-size: 0.875rem;
|
|
192
|
+
}
|
|
193
|
+
|
|
146
194
|
.psdk-horizontal-stepper {
|
|
147
195
|
background-color: transparent;
|
|
148
196
|
display: block;
|
|
@@ -4,6 +4,8 @@ import { FormGroup } from '@angular/forms';
|
|
|
4
4
|
import { Utils } from '@pega/angular-sdk-components';
|
|
5
5
|
import { ComponentMapperComponent } from '@pega/angular-sdk-components';
|
|
6
6
|
|
|
7
|
+
type StepIndicator = 'horizontal' | 'vertical' | 'vertical-start';
|
|
8
|
+
|
|
7
9
|
@Component({
|
|
8
10
|
selector: 'app-multi-step',
|
|
9
11
|
templateUrl: './multi-step.component.html',
|
|
@@ -18,6 +20,7 @@ export class MultiStepComponent implements OnInit {
|
|
|
18
20
|
@Input() arSecondaryButtons$: any[];
|
|
19
21
|
@Input() arChildren$: any[];
|
|
20
22
|
@Input() bIsVertical$: boolean;
|
|
23
|
+
@Input() stepIndicator$?: StepIndicator;
|
|
21
24
|
@Input() arCurrentStepIndicies$: number[];
|
|
22
25
|
@Input() arNavigationSteps$: any[];
|
|
23
26
|
@Output() actionButtonClick: EventEmitter<any> = new EventEmitter();
|
|
@@ -38,6 +41,14 @@ export class MultiStepComponent implements OnInit {
|
|
|
38
41
|
this.actionButtonClick.emit(oData);
|
|
39
42
|
}
|
|
40
43
|
|
|
44
|
+
isVerticalLayout(): boolean {
|
|
45
|
+
return this.stepIndicator$ === 'vertical' || this.stepIndicator$ === 'vertical-start';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
isHorizontalLayout(): boolean {
|
|
49
|
+
return !this.isVerticalLayout();
|
|
50
|
+
}
|
|
51
|
+
|
|
41
52
|
_getVIconClass(status): string {
|
|
42
53
|
if (status == 'current') {
|
|
43
54
|
return 'psdk-vertical-step-icon-selected';
|
|
@@ -3,17 +3,28 @@ import { CommonModule } from '@angular/common';
|
|
|
3
3
|
import { FormGroup } from '@angular/forms';
|
|
4
4
|
import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
|
|
5
5
|
import { Utils } from '@pega/angular-sdk-components';
|
|
6
|
-
import { getAllFields } from '@pega/angular-sdk-components';
|
|
7
6
|
import { ComponentMapperComponent } from '@pega/angular-sdk-components';
|
|
8
7
|
|
|
9
|
-
const NO_HEADER_TEMPLATES = [
|
|
8
|
+
const NO_HEADER_TEMPLATES = [
|
|
9
|
+
'SubTabs',
|
|
10
|
+
'SimpleTable',
|
|
11
|
+
'Details',
|
|
12
|
+
'DetailsTwoColumn',
|
|
13
|
+
'DetailsThreeColumn',
|
|
14
|
+
'NarrowWideDetails',
|
|
15
|
+
'WideNarrowDetails',
|
|
16
|
+
'Confirmation',
|
|
17
|
+
'DynamicTabs',
|
|
18
|
+
'DetailsSubTabs',
|
|
19
|
+
'ListView'
|
|
20
|
+
];
|
|
21
|
+
|
|
10
22
|
const DETAILS_TEMPLATES = [
|
|
11
23
|
'Details',
|
|
12
|
-
'DetailsFields',
|
|
13
24
|
'DetailsOneColumn',
|
|
14
|
-
'DetailsSubTabs',
|
|
15
|
-
'DetailsThreeColumn',
|
|
16
25
|
'DetailsTwoColumn',
|
|
26
|
+
'DetailsThreeColumn',
|
|
27
|
+
'DetailsSubTabs',
|
|
17
28
|
'NarrowWideDetails',
|
|
18
29
|
'WideNarrowDetails'
|
|
19
30
|
];
|
|
@@ -157,7 +168,7 @@ export class ViewComponent implements OnInit, OnDestroy, OnChanges {
|
|
|
157
168
|
this.showLabel$ =
|
|
158
169
|
this.inheritedProps$.showLabel !== undefined
|
|
159
170
|
? this.inheritedProps$.showLabel
|
|
160
|
-
: this.configProps$.showLabel
|
|
171
|
+
: (this.configProps$.showLabel ?? isDetailsTemplate(this.templateName$));
|
|
161
172
|
this.arChildren$ = this.pConn$.getChildren();
|
|
162
173
|
this.visibility$ = this.configProps$.visibility ?? this.visibility$;
|
|
163
174
|
|
|
@@ -183,39 +194,6 @@ export class ViewComponent implements OnInit, OnDestroy, OnChanges {
|
|
|
183
194
|
// console.log("-->view update: " + this.angularPConnect.getComponentID(this) + ", template: " + this.templateName$ + ", kids: " + kidList);
|
|
184
195
|
}
|
|
185
196
|
|
|
186
|
-
// JA - adapting additionalProps from Nebula/Constellation version which uses static methods
|
|
187
|
-
// on the component classes stored in PComponents (that Angular doesn't have)...
|
|
188
|
-
additionalProps(state: any, getPConnect: any) {
|
|
189
|
-
let propObj = {};
|
|
190
|
-
|
|
191
|
-
// We already have the template name in this.templateName$
|
|
192
|
-
if (this.templateName$ !== '') {
|
|
193
|
-
let allFields = {};
|
|
194
|
-
|
|
195
|
-
// These uses are adapted from Nebula/Constellation CaseSummary.additionalProps
|
|
196
|
-
switch (this.templateName$) {
|
|
197
|
-
case 'CaseSummary':
|
|
198
|
-
allFields = getAllFields(getPConnect);
|
|
199
|
-
// eslint-disable-next-line no-case-declarations
|
|
200
|
-
const unresFields = {
|
|
201
|
-
primaryFields: allFields[0],
|
|
202
|
-
secondaryFields: allFields[1]
|
|
203
|
-
};
|
|
204
|
-
propObj = getPConnect.resolveConfigProps(unresFields);
|
|
205
|
-
break;
|
|
206
|
-
|
|
207
|
-
case 'Details':
|
|
208
|
-
allFields = getAllFields(getPConnect);
|
|
209
|
-
propObj = { fields: allFields[0] };
|
|
210
|
-
break;
|
|
211
|
-
default:
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return propObj;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
197
|
ngOnDestroy(): void {
|
|
220
198
|
if (this.angularPConnectData.unsubscribeFn) {
|
|
221
199
|
this.angularPConnectData.unsubscribeFn();
|
|
@@ -11,7 +11,10 @@ export class DetailsTemplateBase implements OnInit, OnDestroy {
|
|
|
11
11
|
protected angularPConnectData: AngularPConnectData = {};
|
|
12
12
|
protected angularPConnect;
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
children: any[] = [];
|
|
15
|
+
propsToUse: any = {};
|
|
16
|
+
showHighlightedData: boolean;
|
|
17
|
+
highlightedDataArr: any = [];
|
|
15
18
|
|
|
16
19
|
constructor(injector: Injector) {
|
|
17
20
|
this.angularPConnect = injector.get(AngularPConnectService);
|
|
@@ -39,23 +42,13 @@ export class DetailsTemplateBase implements OnInit, OnDestroy {
|
|
|
39
42
|
const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this);
|
|
40
43
|
|
|
41
44
|
// Only call updateSelf when the component should update
|
|
42
|
-
if (bUpdateSelf
|
|
45
|
+
if (bUpdateSelf) {
|
|
43
46
|
this.updateSelf();
|
|
44
47
|
}
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
hasRawMetadataChanged(): boolean {
|
|
51
|
-
const newChildrenMetadata = this.fetchChildrenMetadata();
|
|
52
|
-
|
|
53
|
-
if (!PCore.isDeepEqual(newChildrenMetadata, this.childrenMetadataOld)) {
|
|
54
|
-
this.childrenMetadataOld = newChildrenMetadata;
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return false;
|
|
50
|
+
updateSelf() {
|
|
51
|
+
this.updateDetailsProps();
|
|
59
52
|
}
|
|
60
53
|
|
|
61
54
|
fetchChildrenMetadata() {
|
|
@@ -67,47 +60,35 @@ export class DetailsTemplateBase implements OnInit, OnDestroy {
|
|
|
67
60
|
});
|
|
68
61
|
}
|
|
69
62
|
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
};
|
|
97
|
-
const theViewCont = PCore.createPConnect(viewContConfig);
|
|
98
|
-
processedFields.push({
|
|
99
|
-
type: theCompType,
|
|
100
|
-
config: thePConn.getConfigProps(),
|
|
101
|
-
pConn: theViewCont?.getPConnect()
|
|
102
|
-
});
|
|
103
|
-
} else {
|
|
104
|
-
processedFields.push({
|
|
105
|
-
type: theCompType,
|
|
106
|
-
config: thePConn.getConfigProps()
|
|
107
|
-
});
|
|
63
|
+
updateDetailsProps() {
|
|
64
|
+
const { label, showLabel, showHighlightedData } = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps());
|
|
65
|
+
this.propsToUse = { label, showLabel, ...this.pConn$.getInheritedProps() };
|
|
66
|
+
this.showHighlightedData = showHighlightedData;
|
|
67
|
+
|
|
68
|
+
this.pConn$.setInheritedProp('displayMode', 'DISPLAY_ONLY');
|
|
69
|
+
this.pConn$.setInheritedProp('readOnly', true);
|
|
70
|
+
|
|
71
|
+
this.children = this.pConn$.getChildren() as any[];
|
|
72
|
+
|
|
73
|
+
// Process highlighted fields for display in the highlighted section
|
|
74
|
+
this.highlightedDataArr = this.processHighlightedFields();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
processHighlightedFields(): any[] {
|
|
78
|
+
if (!this.showHighlightedData) return [];
|
|
79
|
+
|
|
80
|
+
const { highlightedData = [] } = (this.pConn$.getRawMetadata() as any).config;
|
|
81
|
+
|
|
82
|
+
return (highlightedData ?? []).map(field => {
|
|
83
|
+
field.config.displayMode = 'STACKED_LARGE_VAL';
|
|
84
|
+
field.config.readOnly = true;
|
|
85
|
+
|
|
86
|
+
if (field.config.value === '@P .pyStatusWork') {
|
|
87
|
+
field.type = 'TextInput';
|
|
88
|
+
field.config.displayAsStatus = true;
|
|
108
89
|
}
|
|
109
|
-
});
|
|
110
90
|
|
|
111
|
-
|
|
91
|
+
return this.pConn$.createComponent(field, '', 0, {}).getPConnect();
|
|
92
|
+
});
|
|
112
93
|
}
|
|
113
94
|
}
|
|
@@ -3,6 +3,7 @@ import { FormGroup } from '@angular/forms';
|
|
|
3
3
|
import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
|
|
4
4
|
import { ComponentMapperComponent } from '@pega/angular-sdk-components';
|
|
5
5
|
import { Utils } from '@pega/angular-sdk-components';
|
|
6
|
+
import { getAllFields } from '@pega/angular-sdk-components';
|
|
6
7
|
|
|
7
8
|
interface CaseSummaryProps {
|
|
8
9
|
// If any, enter additional props that only exist on this component
|
|
@@ -73,7 +74,20 @@ export class CaseSummaryComponent implements OnInit, OnDestroy, OnChanges {
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
updateSelf() {
|
|
77
|
+
this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as CaseSummaryProps;
|
|
76
78
|
this.generatePrimaryAndSecondaryFields();
|
|
79
|
+
this.status$ = this.configProps$.status;
|
|
80
|
+
this.bShowStatus$ = this.configProps$.showStatus;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
additionalProps() {
|
|
84
|
+
const allFields = getAllFields(this.pConn$);
|
|
85
|
+
const fields = {
|
|
86
|
+
primaryFields: allFields[0],
|
|
87
|
+
secondaryFields: allFields[1]
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
return this.pConn$.resolveConfigProps(fields);
|
|
77
91
|
}
|
|
78
92
|
|
|
79
93
|
ngOnChanges() {
|
|
@@ -86,7 +100,7 @@ export class CaseSummaryComponent implements OnInit, OnDestroy, OnChanges {
|
|
|
86
100
|
|
|
87
101
|
for (const oField of this.arChildren$[0].getPConnect().getChildren()) {
|
|
88
102
|
const kid = oField.getPConnect();
|
|
89
|
-
this.primaryFields$.push(kid.resolveConfigProps(kid.getRawMetadata()));
|
|
103
|
+
this.primaryFields$.push({ ...kid.resolveConfigProps(kid.getRawMetadata()), kid });
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
const secondarySummaryFields = this.prepareCaseSummaryData(this.arChildren$[1].getPConnect());
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
|
|
18
18
|
<div class="psdk-case-view-buttons">
|
|
19
19
|
<button *ngIf="editAction" mat-raised-button color="secondary" (click)="_editClick()">{{ localizedVal('Edit', localeCategory) }}</button>
|
|
20
|
-
<button mat-raised-button color="secondary" [matMenuTriggerFor]="actionMenu"
|
|
20
|
+
<button mat-raised-button color="secondary" [matMenuTriggerFor]="actionMenu" [disabled]="bActionsMenuDisabled$">
|
|
21
|
+
{{ localizedVal('Actions...', localeCategory) }}
|
|
22
|
+
</button>
|
|
21
23
|
<mat-menu #actionMenu="matMenu" overlapTrigger="false">
|
|
22
24
|
<ng-container *ngFor="let action of arAvailableActions$">
|
|
23
25
|
<button mat-menu-item (click)="_menuActionClick(action)">
|
|
@@ -29,6 +31,16 @@
|
|
|
29
31
|
{{ process.name }}
|
|
30
32
|
</button>
|
|
31
33
|
</ng-container>
|
|
34
|
+
<ng-container *ngFor="let action of arDataObjectActions$">
|
|
35
|
+
<button mat-menu-item (click)="_menuDataObjectActionClick(action)">
|
|
36
|
+
{{ localizedVal(action.name, '', localeKey) }}
|
|
37
|
+
</button>
|
|
38
|
+
</ng-container>
|
|
39
|
+
<ng-container *ngFor="let action of arCreateCaseActions$">
|
|
40
|
+
<button mat-menu-item (click)="_menuCreateCaseActionClick(action)">
|
|
41
|
+
{{ localizedVal(action.name, '', localeKey) }}
|
|
42
|
+
</button>
|
|
43
|
+
</ng-container>
|
|
32
44
|
</mat-menu>
|
|
33
45
|
</div>
|
|
34
46
|
|
|
@@ -1,24 +1,133 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChangeDetectorRef } from '@angular/core';
|
|
2
2
|
|
|
3
3
|
import { CaseViewComponent } from './case-view.component';
|
|
4
4
|
|
|
5
5
|
describe('CaseViewComponent', () => {
|
|
6
6
|
let component: CaseViewComponent;
|
|
7
|
-
let
|
|
7
|
+
let actionsApi: { openDataObjectAction: jasmine.Spy; createWork: jasmine.Spy };
|
|
8
|
+
let dataInfoActions: any;
|
|
9
|
+
let dataRecord: any;
|
|
10
|
+
let caseInfo: any;
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const tabsChild = {
|
|
13
|
+
getPConnect: () => ({
|
|
14
|
+
getRawMetadata: () => ({ type: 'region', name: 'Tabs' }),
|
|
15
|
+
getChildren: () => []
|
|
16
|
+
})
|
|
17
|
+
};
|
|
14
18
|
|
|
15
19
|
beforeEach(() => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
(globalThis as any).PCore = {
|
|
21
|
+
getLocaleUtils: () => ({ getLocaleValue: (value: string) => value })
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
actionsApi = {
|
|
25
|
+
openDataObjectAction: jasmine.createSpy('openDataObjectAction'),
|
|
26
|
+
createWork: jasmine.createSpy('createWork')
|
|
27
|
+
};
|
|
28
|
+
dataInfoActions = undefined;
|
|
29
|
+
dataRecord = { PlanID: 'P-1', CustomerID: 'C-9' };
|
|
30
|
+
caseInfo = { ID: 'C-1', availableActions: [], availableProcesses: [] };
|
|
31
|
+
|
|
32
|
+
const cdRef = { detectChanges: () => {}, markForCheck: () => {} } as unknown as ChangeDetectorRef;
|
|
33
|
+
const utils = { getImageSrc: () => '', getSDKStaticContentUrl: () => '' } as any;
|
|
34
|
+
|
|
35
|
+
component = new CaseViewComponent(cdRef, {} as any, utils);
|
|
36
|
+
component.pConn$ = {
|
|
37
|
+
resolveConfigProps: (props: any) => props,
|
|
38
|
+
getConfigProps: () => ({ icon: 'case', header: 'Header', subheader: 'ID-1' }),
|
|
39
|
+
getCaseInfo: () => ({ getClassName: () => 'My-Class', getName: () => 'My Case' }),
|
|
40
|
+
getChildren: () => [tabsChild],
|
|
41
|
+
getLocalizationService: () => ({ getLocalizedText: (value: string) => value }),
|
|
42
|
+
getDataObject: () => ({ caseInfo }),
|
|
43
|
+
getValue: (prop: string, context?: string) => {
|
|
44
|
+
if (prop === '.actions' && context === 'dataInfo') return dataInfoActions;
|
|
45
|
+
if (prop === '.content' && context === 'dataInfo') return dataRecord;
|
|
46
|
+
if (prop === '.classID' && context === 'dataInfo.content') return 'My-Data-Class';
|
|
47
|
+
if (context === '') return dataRecord[prop.slice(1)];
|
|
48
|
+
return undefined;
|
|
49
|
+
},
|
|
50
|
+
getActionsApi: () => actionsApi
|
|
51
|
+
} as any;
|
|
52
|
+
component.localizedVal = (value: string) => value;
|
|
19
53
|
});
|
|
20
54
|
|
|
21
55
|
it('should create', () => {
|
|
22
56
|
expect(component).toBeTruthy();
|
|
23
57
|
});
|
|
58
|
+
|
|
59
|
+
it('lists data object actions published under dataInfo', () => {
|
|
60
|
+
dataInfoActions = {
|
|
61
|
+
availableActions: [{ ID: 'Edit', name: 'Edit' }],
|
|
62
|
+
availableCreateCaseActions: [{ ID: 'My-Work-Class', name: 'Request Plan Change' }]
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
component.fullUpdate();
|
|
66
|
+
|
|
67
|
+
expect(component.arDataObjectActions$.length).toBe(1);
|
|
68
|
+
expect(component.arCreateCaseActions$.length).toBe(1);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('falls back to empty arrays when the dataInfo context is absent', () => {
|
|
72
|
+
dataInfoActions = undefined;
|
|
73
|
+
|
|
74
|
+
component.fullUpdate();
|
|
75
|
+
|
|
76
|
+
expect(component.arDataObjectActions$).toEqual([]);
|
|
77
|
+
expect(component.arCreateCaseActions$).toEqual([]);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('disables the actions menu when no action of any kind is available', () => {
|
|
81
|
+
component.fullUpdate();
|
|
82
|
+
|
|
83
|
+
expect(component.bActionsMenuDisabled$).toBeTrue();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('enables the actions menu when only data object actions are available', () => {
|
|
87
|
+
dataInfoActions = { availableActions: [{ ID: 'Edit', name: 'Edit' }] };
|
|
88
|
+
|
|
89
|
+
component.fullUpdate();
|
|
90
|
+
|
|
91
|
+
expect(component.bActionsMenuDisabled$).toBeFalse();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('picks up case actions that arrive after the first update, without a case ID change', () => {
|
|
95
|
+
component.fullUpdate();
|
|
96
|
+
expect(component.bActionsMenuDisabled$).toBeTrue();
|
|
97
|
+
expect(component.editAction).toBeUndefined();
|
|
98
|
+
|
|
99
|
+
caseInfo.availableActions = [{ ID: 'pyUpdateCaseDetails', name: 'Edit details' }];
|
|
100
|
+
component.updateCaseActions();
|
|
101
|
+
|
|
102
|
+
expect(component.arAvailableActions$.length).toBe(1);
|
|
103
|
+
expect(component.editAction).toBeTruthy();
|
|
104
|
+
expect(component.bActionsMenuDisabled$).toBeFalse();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('opens a data object action with the record class and content', () => {
|
|
108
|
+
component._menuDataObjectActionClick({ ID: 'updateCVV', name: 'Update CVV' });
|
|
109
|
+
|
|
110
|
+
expect(actionsApi.openDataObjectAction).toHaveBeenCalledWith('My-Data-Class', dataRecord, 'updateCVV', 'Update CVV');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('starts a new case with starting fields nested under the target reference field', () => {
|
|
114
|
+
component._menuCreateCaseActionClick({
|
|
115
|
+
ID: 'My-Work-Class',
|
|
116
|
+
name: 'Request Plan Change',
|
|
117
|
+
targetDataReferenceField: {
|
|
118
|
+
field: 'PlanRef',
|
|
119
|
+
inputs: [{ linkedField: 'PlanID' }, { linkedField: 'CustomerID' }]
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(actionsApi.createWork).toHaveBeenCalledWith('My-Work-Class', {
|
|
124
|
+
startingFields: { PlanRef: { PlanID: 'P-1', CustomerID: 'C-9' } }
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('starts a new case with no starting fields when the action declares no inputs', () => {
|
|
129
|
+
component._menuCreateCaseActionClick({ ID: 'My-Work-Class', name: 'Request Plan Change' });
|
|
130
|
+
|
|
131
|
+
expect(actionsApi.createWork).toHaveBeenCalledWith('My-Work-Class', { startingFields: {} });
|
|
132
|
+
});
|
|
24
133
|
});
|
|
@@ -8,6 +8,7 @@ import { interval } from 'rxjs';
|
|
|
8
8
|
import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
|
|
9
9
|
import { Utils } from '@pega/angular-sdk-components';
|
|
10
10
|
import { ComponentMapperComponent } from '@pega/angular-sdk-components';
|
|
11
|
+
import { CreateCaseAction, DataObjectAction, DataObjectActions } from '@pega/angular-sdk-components';
|
|
11
12
|
|
|
12
13
|
interface CaseViewProps {
|
|
13
14
|
// If any, enter additional props that only exist on this component
|
|
@@ -45,6 +46,9 @@ export class CaseViewComponent implements OnInit, OnDestroy {
|
|
|
45
46
|
|
|
46
47
|
arAvailableActions$: any[] = [];
|
|
47
48
|
arAvailabeProcesses$: any[] = [];
|
|
49
|
+
arDataObjectActions$: DataObjectAction[] = [];
|
|
50
|
+
arCreateCaseActions$: CreateCaseAction[] = [];
|
|
51
|
+
bActionsMenuDisabled$ = true;
|
|
48
52
|
|
|
49
53
|
caseSummaryPConn$: any;
|
|
50
54
|
currentCaseID = '';
|
|
@@ -98,10 +102,31 @@ export class CaseViewComponent implements OnInit, OnDestroy {
|
|
|
98
102
|
sessionStorage.setItem('okToInitFlowContainer', 'true');
|
|
99
103
|
} else {
|
|
100
104
|
this.updateHeaderAndSummary();
|
|
105
|
+
this.updateCaseActions();
|
|
101
106
|
}
|
|
102
107
|
}
|
|
103
108
|
}
|
|
104
109
|
|
|
110
|
+
// React re-reads every action source on each render. Here fullUpdate is gated on a case ID
|
|
111
|
+
// change and so runs once, while actions (and a data object's `dataInfo.actions`) arrive
|
|
112
|
+
// later, so they are all refreshed on every store update instead.
|
|
113
|
+
updateCaseActions() {
|
|
114
|
+
const caseInfo = this.pConn$.getDataObject()?.caseInfo ?? {};
|
|
115
|
+
this.arAvailableActions$ = caseInfo.availableActions ?? [];
|
|
116
|
+
this.arAvailabeProcesses$ = caseInfo.availableProcesses ?? [];
|
|
117
|
+
this.editAction = this.arAvailableActions$.find(action => action.ID === 'pyUpdateCaseDetails');
|
|
118
|
+
|
|
119
|
+
const dataInfoActions: DataObjectActions = this.pConn$.getValue('.actions', 'dataInfo') ?? {};
|
|
120
|
+
this.arDataObjectActions$ = dataInfoActions.availableActions ?? [];
|
|
121
|
+
this.arCreateCaseActions$ = dataInfoActions.availableCreateCaseActions ?? [];
|
|
122
|
+
|
|
123
|
+
this.bActionsMenuDisabled$ =
|
|
124
|
+
this.arAvailableActions$.length === 0 &&
|
|
125
|
+
this.arAvailabeProcesses$.length === 0 &&
|
|
126
|
+
this.arDataObjectActions$.length === 0 &&
|
|
127
|
+
this.arCreateCaseActions$.length === 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
105
130
|
hasCaseIDChanged(): boolean {
|
|
106
131
|
if (this.currentCaseID !== this.pConn$.getDataObject().caseInfo.ID) {
|
|
107
132
|
this.currentCaseID = this.pConn$.getDataObject().caseInfo.ID;
|
|
@@ -144,9 +169,8 @@ export class CaseViewComponent implements OnInit, OnDestroy {
|
|
|
144
169
|
|
|
145
170
|
const caseInfo = this.pConn$.getDataObject().caseInfo;
|
|
146
171
|
this.currentCaseID = caseInfo.ID;
|
|
147
|
-
|
|
148
|
-
this.
|
|
149
|
-
this.arAvailabeProcesses$ = caseInfo?.availableProcesses ? caseInfo.availableProcesses : [];
|
|
172
|
+
|
|
173
|
+
this.updateCaseActions();
|
|
150
174
|
|
|
151
175
|
this.svgCase$ = this.utils.getImageSrc(this.configProps$.icon, this.utils.getSDKStaticContentUrl());
|
|
152
176
|
|
|
@@ -218,4 +242,29 @@ export class CaseViewComponent implements OnInit, OnDestroy {
|
|
|
218
242
|
|
|
219
243
|
openProcessAction(data.ID, { ...data });
|
|
220
244
|
}
|
|
245
|
+
|
|
246
|
+
_menuDataObjectActionClick(action: DataObjectAction) {
|
|
247
|
+
const actionsAPI = this.pConn$.getActionsApi();
|
|
248
|
+
const openDataObjectAction = actionsAPI.openDataObjectAction.bind(actionsAPI);
|
|
249
|
+
const classID = this.pConn$.getValue('.classID', 'dataInfo.content');
|
|
250
|
+
const dataRecord = this.pConn$.getValue('.content', 'dataInfo');
|
|
251
|
+
|
|
252
|
+
openDataObjectAction(classID, dataRecord, action.ID, this.localizedVal(action.name, '', this.localeKey));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
_menuCreateCaseActionClick(action: CreateCaseAction) {
|
|
256
|
+
const actionsAPI = this.pConn$.getActionsApi();
|
|
257
|
+
const createWork = actionsAPI.createWork.bind(actionsAPI);
|
|
258
|
+
const { field, inputs } = action.targetDataReferenceField ?? {};
|
|
259
|
+
const startingFields: Record<string, any> = {};
|
|
260
|
+
|
|
261
|
+
// The engine expects the linked values nested under the target reference field.
|
|
262
|
+
if (field) {
|
|
263
|
+
inputs?.forEach(input => {
|
|
264
|
+
startingFields[field] = { ...startingFields[field], [input.linkedField]: this.pConn$.getValue(`.${input.linkedField}`, '') };
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
createWork(action.ID, { startingFields });
|
|
269
|
+
}
|
|
221
270
|
}
|