@pega/dx-component-builder-sdk 0.23.12 → 0.23.14
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/package.json +1 -1
- package/src/constants.js +12 -0
- package/src/tasks/create/templates/SDK-React/field/Boolean/index.tsx.mustache +23 -21
- package/src/tasks/create/templates/SDK-React/field/Date/index.tsx.mustache +24 -26
- package/src/tasks/create/templates/SDK-React/field/DateTime/index.tsx.mustache +20 -22
- package/src/tasks/create/templates/SDK-React/field/Decimal/index.tsx.mustache +3 -4
- package/src/tasks/create/templates/SDK-React/field/Decimal-Currency/index.tsx.mustache +3 -4
- package/src/tasks/create/templates/SDK-React/field/Decimal-Percentage/index.tsx.mustache +3 -4
- package/src/tasks/create/templates/SDK-React/field/Integer/index.tsx.mustache +3 -4
- package/src/tasks/create/templates/SDK-React/field/Picklist/index.tsx.mustache +3 -4
- package/src/tasks/create/templates/SDK-React/field/Picklist-Autocomplete/index.tsx.mustache +31 -32
- package/src/tasks/create/templates/SDK-React/field/Picklist-RadioButtons/index.tsx.mustache +22 -23
- package/src/tasks/create/templates/SDK-React/field/Text/index.tsx.mustache +18 -19
- package/src/tasks/create/templates/SDK-React/field/Text-Email/index.tsx.mustache +26 -27
- package/src/tasks/create/templates/SDK-React/field/Text-Input/index.tsx.mustache +18 -19
- package/src/tasks/create/templates/SDK-React/field/Text-Paragraph/index.tsx.mustache +21 -22
- package/src/tasks/create/templates/SDK-React/field/Text-Phone/index.tsx.mustache +39 -40
- package/src/tasks/create/templates/SDK-React/field/Text-URL/index.tsx.mustache +19 -20
- package/src/tasks/create/templates/SDK-React/field/TimeOfDay/index.tsx.mustache +4 -5
- package/src/tasks/create/templates/SDK-React/template/DETAILS/index.tsx.mustache +19 -20
- package/src/tasks/create/templates/SDK-React/template/DETAILS-region/index.tsx.mustache +19 -20
- package/src/tasks/create/templates/SDK-React/template/FORM/index.tsx.mustache +6 -7
- package/src/tasks/create/templates/SDK-React/template/FORM-region/index.tsx.mustache +8 -9
- package/src/tasks/create/templates/SDK-React/template/PAGE/index.tsx.mustache +4 -5
- package/src/tasks/create/templates/SDK-React/widget/CASE/index.tsx.mustache +10 -11
- package/src/tasks/create/templates/SDK-React/widget/PAGE/index.tsx.mustache +23 -24
- package/src/tasks/create/templates/SDK-React/widget/PAGE-CASE/index.tsx.mustache +37 -37
- package/src/tasks/validator/index.js +52 -47
- package/tests/assets/sdk-a/components/create/override-sdk/designSystemExtension/material-summary-item/material-summary-item.component.html +2 -2
- package/tests/assets/sdk-a/components/create/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.html +33 -0
- package/tests/assets/sdk-a/components/create/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.scss +19 -0
- package/tests/assets/sdk-a/components/create/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.spec.ts +24 -0
- package/tests/assets/sdk-a/components/create/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.ts +89 -0
- package/tests/assets/sdk-a/components/create/override-sdk/field/dropdown/dropdown.component.ts +1 -1
- package/tests/assets/sdk-a/components/create/override-sdk/field/rich-text/rich-text.component.html +20 -0
- package/tests/assets/sdk-a/components/create/override-sdk/field/rich-text/rich-text.component.scss +0 -0
- package/tests/assets/sdk-a/components/create/override-sdk/field/rich-text/rich-text.component.spec.ts +24 -0
- package/tests/assets/sdk-a/components/create/override-sdk/field/rich-text/rich-text.component.ts +131 -0
- package/tests/assets/sdk-a/components/create/override-sdk/widget/file-utility/file-utility.component.ts +31 -18
- package/tests/assets/sdk-a/components/createAll/override-sdk/designSystemExtension/material-summary-item/material-summary-item.component.html +2 -2
- package/tests/assets/sdk-a/components/createAll/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.html +33 -0
- package/tests/assets/sdk-a/components/createAll/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.scss +19 -0
- package/tests/assets/sdk-a/components/createAll/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.spec.ts +24 -0
- package/tests/assets/sdk-a/components/createAll/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.ts +89 -0
- package/tests/assets/sdk-a/components/createAll/override-sdk/field/dropdown/dropdown.component.ts +1 -1
- package/tests/assets/sdk-a/components/createAll/override-sdk/field/rich-text/rich-text.component.html +20 -0
- package/tests/assets/sdk-a/components/createAll/override-sdk/field/rich-text/rich-text.component.scss +0 -0
- package/tests/assets/sdk-a/components/createAll/override-sdk/field/rich-text/rich-text.component.spec.ts +24 -0
- package/tests/assets/sdk-a/components/createAll/override-sdk/field/rich-text/rich-text.component.ts +131 -0
- package/tests/assets/sdk-a/components/createAll/override-sdk/widget/file-utility/file-utility.component.ts +31 -18
package/tests/assets/sdk-a/components/create/override-sdk/field/rich-text/rich-text.component.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Component, OnInit, Input, forwardRef, OnDestroy } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormGroup, ReactiveFormsModule } from '@angular/forms';
|
|
4
|
+
import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
|
|
5
|
+
import { Utils } from '@pega/angular-sdk-components';
|
|
6
|
+
import { ComponentMapperComponent } from '@pega/angular-sdk-components';
|
|
7
|
+
import { handleEvent } from '@pega/angular-sdk-components';
|
|
8
|
+
import { PConnFieldProps } from '@pega/angular-sdk-components';
|
|
9
|
+
|
|
10
|
+
interface RichTextProps extends PConnFieldProps {
|
|
11
|
+
// If any, enter additional props that only exist on RichText here
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@Component({
|
|
15
|
+
selector: 'app-rich-text',
|
|
16
|
+
templateUrl: './rich-text.component.html',
|
|
17
|
+
styleUrls: ['./rich-text.component.scss'],
|
|
18
|
+
standalone: true,
|
|
19
|
+
imports: [CommonModule, ReactiveFormsModule, forwardRef(() => ComponentMapperComponent)]
|
|
20
|
+
})
|
|
21
|
+
export class RichTextComponent implements OnInit, OnDestroy {
|
|
22
|
+
@Input() pConn$: typeof PConnect;
|
|
23
|
+
@Input() formGroup$: FormGroup;
|
|
24
|
+
|
|
25
|
+
// Used with AngularPConnect
|
|
26
|
+
angularPConnectData: AngularPConnectData = {};
|
|
27
|
+
configProps$: RichTextProps;
|
|
28
|
+
|
|
29
|
+
label$ = '';
|
|
30
|
+
value$ = '';
|
|
31
|
+
bRequired$ = false;
|
|
32
|
+
bReadonly$ = false;
|
|
33
|
+
bDisabled$ = false;
|
|
34
|
+
bVisible$ = true;
|
|
35
|
+
displayMode$?: string = '';
|
|
36
|
+
controlName$: string;
|
|
37
|
+
testId: string;
|
|
38
|
+
helperText: string;
|
|
39
|
+
placeholder: any;
|
|
40
|
+
info: any;
|
|
41
|
+
error: boolean;
|
|
42
|
+
status: any;
|
|
43
|
+
|
|
44
|
+
constructor(
|
|
45
|
+
private angularPConnect: AngularPConnectService,
|
|
46
|
+
private utils: Utils
|
|
47
|
+
) {}
|
|
48
|
+
|
|
49
|
+
ngOnInit(): void {
|
|
50
|
+
// First thing in initialization is registering and subscribing to the AngularPConnect service
|
|
51
|
+
this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange);
|
|
52
|
+
|
|
53
|
+
// call updateSelf when initializing
|
|
54
|
+
this.checkAndUpdate();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
ngOnDestroy(): void {
|
|
58
|
+
if (this.angularPConnectData.unsubscribeFn) {
|
|
59
|
+
this.angularPConnectData.unsubscribeFn();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Callback passed when subscribing to store change
|
|
64
|
+
onStateChange() {
|
|
65
|
+
this.checkAndUpdate();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
checkAndUpdate() {
|
|
69
|
+
// Should always check the bridge to see if the component should
|
|
70
|
+
// update itself (re-render)
|
|
71
|
+
const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this);
|
|
72
|
+
|
|
73
|
+
// ONLY call updateSelf when the component should update
|
|
74
|
+
if (bUpdateSelf) {
|
|
75
|
+
this.updateSelf();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// updateSelf
|
|
80
|
+
updateSelf(): void {
|
|
81
|
+
// moved this from ngOnInit() and call this from there instead...
|
|
82
|
+
this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as RichTextProps;
|
|
83
|
+
const stateProps: any = this.pConn$.getStateProps();
|
|
84
|
+
this.status = stateProps?.status;
|
|
85
|
+
|
|
86
|
+
if (this.configProps$.value != undefined) {
|
|
87
|
+
this.value$ = this.configProps$.value;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.testId = this.configProps$.testId;
|
|
91
|
+
this.displayMode$ = this.configProps$.displayMode;
|
|
92
|
+
this.label$ = this.configProps$.label;
|
|
93
|
+
this.placeholder = this.configProps$.placeholder;
|
|
94
|
+
this.info = stateProps?.validatemessage || this.configProps$.helperText;
|
|
95
|
+
this.error = stateProps?.status === 'error';
|
|
96
|
+
|
|
97
|
+
if (this.configProps$.required != null) {
|
|
98
|
+
this.bRequired$ = this.utils.getBooleanValue(this.configProps$.required);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (this.configProps$.visibility != null) {
|
|
102
|
+
this.bVisible$ = this.utils.getBooleanValue(this.configProps$.visibility);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (this.configProps$.disabled != undefined) {
|
|
106
|
+
this.bDisabled$ = this.utils.getBooleanValue(this.configProps$.disabled);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (this.configProps$.readOnly != null) {
|
|
110
|
+
this.bReadonly$ = this.utils.getBooleanValue(this.configProps$.readOnly);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
fieldOnChange() {
|
|
115
|
+
if (this.status === 'error') {
|
|
116
|
+
const property = (this.pConn$.getStateProps() as any).value;
|
|
117
|
+
this.pConn$.clearErrorMessages({
|
|
118
|
+
property,
|
|
119
|
+
category: '',
|
|
120
|
+
context: ''
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
fieldOnBlur(editorValue: any) {
|
|
126
|
+
// PConnect wants to use eventHandler for onBlur
|
|
127
|
+
const actionsApi = this.pConn$?.getActionsApi();
|
|
128
|
+
const propName = (this.pConn$?.getStateProps() as any).value;
|
|
129
|
+
handleEvent(actionsApi, 'changeNblur', propName, editorValue);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -149,24 +149,30 @@ export class FileUtilityComponent implements OnInit, OnDestroy {
|
|
|
149
149
|
this.lu_bLoading$ = true;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
attachmentUtils
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
})
|
|
163
|
-
.catch(console.error);
|
|
152
|
+
const arFiles: any = Array.from(files);
|
|
153
|
+
|
|
154
|
+
Promise.allSettled(
|
|
155
|
+
arFiles.map(file => attachmentUtils.uploadAttachment(file, this.onUploadProgress, this.errorHandler, this.pConn$.getContextName()))
|
|
156
|
+
)
|
|
157
|
+
.then((fileResponses: any) => {
|
|
158
|
+
const uploadedFiles: any = [];
|
|
159
|
+
fileResponses.forEach(fileResponse => {
|
|
160
|
+
if (fileResponse.status === 'fulfilled') {
|
|
161
|
+
uploadedFiles.push(fileResponse.value);
|
|
164
162
|
}
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
|
|
163
|
+
});
|
|
164
|
+
if (uploadedFiles.length > 0) {
|
|
165
|
+
(attachmentUtils.linkAttachmentsToCase(caseID, uploadedFiles, 'File', this.pConn$.getContextName()) as Promise<any>)
|
|
166
|
+
.then(() => {
|
|
167
|
+
this.refreshAttachments();
|
|
168
|
+
})
|
|
169
|
+
.catch();
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
.catch();
|
|
168
173
|
|
|
169
174
|
this.arFileList$ = [];
|
|
175
|
+
this.lu_bLoading$ = false;
|
|
170
176
|
}
|
|
171
177
|
|
|
172
178
|
refreshAttachments() {
|
|
@@ -691,9 +697,16 @@ export class FileUtilityComponent implements OnInit, OnDestroy {
|
|
|
691
697
|
if (caseID) {
|
|
692
698
|
this.lu_bLoading$ = true;
|
|
693
699
|
|
|
694
|
-
this.fetchCaseAttachments(caseID)
|
|
695
|
-
|
|
696
|
-
|
|
700
|
+
this.fetchCaseAttachments(caseID)
|
|
701
|
+
.then(resp => {
|
|
702
|
+
this.handleAttachmentsResponse(resp);
|
|
703
|
+
})
|
|
704
|
+
.catch(err => {
|
|
705
|
+
console.log(err);
|
|
706
|
+
})
|
|
707
|
+
.finally(() => {
|
|
708
|
+
this.lu_bLoading$ = false;
|
|
709
|
+
});
|
|
697
710
|
}
|
|
698
711
|
}
|
|
699
712
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
</div>
|
|
17
17
|
<div class="psdk-utility-card-actions">
|
|
18
18
|
<div *ngIf="menuIconOverride$ == ''; else showCustom">
|
|
19
|
-
<button mat-icon-button [matMenuTriggerFor]="actionMenu">
|
|
19
|
+
<button id="setting-button" mat-icon-button [matMenuTriggerFor]="actionMenu">
|
|
20
20
|
<img class="psdk-utility-card-action-svg-icon" src="{{ settingsSvgIcon$ }}" />
|
|
21
21
|
</button>
|
|
22
22
|
<mat-menu #actionMenu="matMenu" overlapTrigger="false">
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
</mat-menu>
|
|
30
30
|
</div>
|
|
31
31
|
<ng-template #showCustom>
|
|
32
|
-
<button mat-icon-button (click)="menuIconOverrideAction$.onClick(item$)">
|
|
32
|
+
<button id="delete-attachment" mat-icon-button (click)="menuIconOverrideAction$.onClick(item$)">
|
|
33
33
|
<img class="psdk-utility-card-action-svg-icon" src="{{ menuIconOverride$ }}" />
|
|
34
34
|
</button>
|
|
35
35
|
</ng-template>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<div [attr.data-test-id]="testId">
|
|
2
|
+
<label [ngClass]="{ 'label-required': required === true }" class="rich-text-label">{{ label }}</label>
|
|
3
|
+
<div class="rich-text-editor" *ngIf="!readonly">
|
|
4
|
+
<editor
|
|
5
|
+
[formControl]="richText"
|
|
6
|
+
[attr.disabled]="disabled"
|
|
7
|
+
[initialValue]="value"
|
|
8
|
+
[init]="{
|
|
9
|
+
base_url: '/tinymce',
|
|
10
|
+
suffix: '.min',
|
|
11
|
+
menubar: false,
|
|
12
|
+
placeholder,
|
|
13
|
+
statusbar: false,
|
|
14
|
+
min_height: 130,
|
|
15
|
+
plugins: ['lists', 'advlist', 'autolink', 'image', 'link', 'autoresize'],
|
|
16
|
+
autoresize_bottom_margin: 0,
|
|
17
|
+
toolbar: disabled ? false : 'blocks | bold italic strikethrough | bullist numlist outdent indent | link image',
|
|
18
|
+
toolbar_location: 'bottom',
|
|
19
|
+
content_style: 'body { font-family:Helvetica, Arial,sans-serif; font-size:14px }',
|
|
20
|
+
branding: false,
|
|
21
|
+
paste_data_images: true,
|
|
22
|
+
file_picker_types: 'image',
|
|
23
|
+
file_picker_callback: filePickerCallback
|
|
24
|
+
}"
|
|
25
|
+
(onBlur)="blur()"
|
|
26
|
+
(onChange)="change($event)"
|
|
27
|
+
></editor>
|
|
28
|
+
<p *ngIf="richText.invalid" [ngClass]="'text-editor-error'">{{ info }}</p>
|
|
29
|
+
</div>
|
|
30
|
+
<div *ngIf="readonly">
|
|
31
|
+
<div class="readonly-richtext-editor" style="margin: 10px 5px" [innerHTML]="value || '--'"></div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.rich-text-label {
|
|
2
|
+
margin: 5px;
|
|
3
|
+
font-size: 16px;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.rich-text-editor {
|
|
7
|
+
margin: 10px 0px;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.label-required::after {
|
|
11
|
+
display: inline;
|
|
12
|
+
content: ' *';
|
|
13
|
+
vertical-align: top;
|
|
14
|
+
color: var(--app-neutral-dark-color);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.text-editor-error {
|
|
18
|
+
color: var(--app-error-light-color);
|
|
19
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { RichTextEditorComponent } from './rich-text-editor.component';
|
|
4
|
+
|
|
5
|
+
describe('RichTextComponent', () => {
|
|
6
|
+
let component: RichTextEditorComponent;
|
|
7
|
+
let fixture: ComponentFixture<RichTextEditorComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(waitForAsync(() => {
|
|
10
|
+
TestBed.configureTestingModule({
|
|
11
|
+
declarations: [RichTextEditorComponent]
|
|
12
|
+
}).compileComponents();
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
fixture = TestBed.createComponent(RichTextEditorComponent);
|
|
17
|
+
component = fixture.componentInstance;
|
|
18
|
+
fixture.detectChanges();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should create', () => {
|
|
22
|
+
expect(component).toBeTruthy();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, OnChanges } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
|
|
4
|
+
import { EditorModule, TINYMCE_SCRIPT_SRC } from '@tinymce/tinymce-angular';
|
|
5
|
+
|
|
6
|
+
declare let tinymce: any;
|
|
7
|
+
|
|
8
|
+
@Component({
|
|
9
|
+
selector: 'app-rich-text-editor',
|
|
10
|
+
templateUrl: './rich-text-editor.component.html',
|
|
11
|
+
styleUrls: ['./rich-text-editor.component.scss'],
|
|
12
|
+
standalone: true,
|
|
13
|
+
imports: [CommonModule, EditorModule, ReactiveFormsModule],
|
|
14
|
+
providers: [{ provide: TINYMCE_SCRIPT_SRC, useValue: 'tinymce/tinymce.min.js' }]
|
|
15
|
+
})
|
|
16
|
+
export class RichTextEditorComponent implements OnChanges {
|
|
17
|
+
@Input() placeholder;
|
|
18
|
+
@Input() disabled;
|
|
19
|
+
@Input() readonly;
|
|
20
|
+
@Input() value;
|
|
21
|
+
@Input() label;
|
|
22
|
+
@Input() required;
|
|
23
|
+
@Input() info;
|
|
24
|
+
@Input() error;
|
|
25
|
+
@Input() testId;
|
|
26
|
+
|
|
27
|
+
@Output() onBlur: EventEmitter<any> = new EventEmitter();
|
|
28
|
+
@Output() onChange: EventEmitter<any> = new EventEmitter();
|
|
29
|
+
|
|
30
|
+
richText = new FormControl();
|
|
31
|
+
|
|
32
|
+
ngOnChanges() {
|
|
33
|
+
if (this.required) {
|
|
34
|
+
this.richText.addValidators(Validators.required);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (this.disabled) {
|
|
38
|
+
this.richText.disable();
|
|
39
|
+
} else {
|
|
40
|
+
this.richText.enable();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (this.value) {
|
|
44
|
+
this.richText.setValue(this.value);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
filePickerCallback = cb => {
|
|
49
|
+
const input = document.createElement('input');
|
|
50
|
+
input.setAttribute('type', 'file');
|
|
51
|
+
input.setAttribute('accept', 'image/*');
|
|
52
|
+
|
|
53
|
+
input.addEventListener('change', (e: any) => {
|
|
54
|
+
const file = e.target.files[0];
|
|
55
|
+
|
|
56
|
+
const reader: any = new FileReader();
|
|
57
|
+
reader.addEventListener('load', () => {
|
|
58
|
+
/*
|
|
59
|
+
Note: Now we need to register the blob in TinyMCEs image blob
|
|
60
|
+
registry. In the next release this part hopefully won't be
|
|
61
|
+
necessary, as we are looking to handle it internally.
|
|
62
|
+
*/
|
|
63
|
+
const blobId = `blobid${new Date().getTime()}`;
|
|
64
|
+
console.log('editorRef', tinymce.activeEditor);
|
|
65
|
+
const blobCache = tinymce.activeEditor.editorUpload.blobCache;
|
|
66
|
+
const base64 = reader.result.split(',')[1];
|
|
67
|
+
const blobInfo = blobCache.create(blobId, file, base64);
|
|
68
|
+
blobCache.add(blobInfo);
|
|
69
|
+
|
|
70
|
+
/* call the callback and populate the Title field with the file name */
|
|
71
|
+
cb(blobInfo.blobUri(), { title: file.name });
|
|
72
|
+
});
|
|
73
|
+
reader.readAsDataURL(file);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
input.click();
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
blur() {
|
|
80
|
+
if (tinymce.activeEditor) {
|
|
81
|
+
const editorValue = tinymce.activeEditor.getContent({ format: 'html' });
|
|
82
|
+
this.onBlur.emit(editorValue);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
change(event) {
|
|
87
|
+
this.onChange.emit(event);
|
|
88
|
+
}
|
|
89
|
+
}
|
package/tests/assets/sdk-a/components/createAll/override-sdk/field/dropdown/dropdown.component.ts
CHANGED
|
@@ -160,7 +160,7 @@ export class DropdownComponent implements OnInit, OnDestroy {
|
|
|
160
160
|
this.componentReference = (this.pConn$.getStateProps() as any).value;
|
|
161
161
|
|
|
162
162
|
// @ts-ignore - parameter “contextName” for getDataObject method should be optional
|
|
163
|
-
const optionsList = this.utils.getOptionList(this.configProps$, this.pConn$.getDataObject());
|
|
163
|
+
const optionsList = [...this.utils.getOptionList(this.configProps$, this.pConn$.getDataObject())];
|
|
164
164
|
optionsList?.unshift({ key: 'Select', value: this.pConn$.getLocalizedValue('Select...', '', '') });
|
|
165
165
|
this.options$ = optionsList;
|
|
166
166
|
if (this.value$ === '' && !this.bReadonly$) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<div *ngIf="displayMode$; else noDisplayMode">
|
|
2
|
+
<component-mapper *ngIf="bVisible$ !== false" name="FieldValueList" [props]="{ label$, value$, displayMode$ }"></component-mapper>
|
|
3
|
+
</div>
|
|
4
|
+
<ng-template #noDisplayMode>
|
|
5
|
+
<div *ngIf="!bReadonly$; else noEdit">
|
|
6
|
+
<div *ngIf="bVisible$">
|
|
7
|
+
<component-mapper
|
|
8
|
+
name="RichTextEditor"
|
|
9
|
+
[props]="{ placeholder, required: bRequired$, disabled: bDisabled$, label: label$, readonly: false, error, info, testId, value: value$ }"
|
|
10
|
+
[parent]="this"
|
|
11
|
+
[outputEvents]="{ onBlur: fieldOnBlur, onChange: fieldOnChange }"
|
|
12
|
+
></component-mapper>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</ng-template>
|
|
16
|
+
<ng-template #noEdit>
|
|
17
|
+
<div *ngIf="bVisible$ !== false">
|
|
18
|
+
<component-mapper name="RichTextEditor" [props]="{ label: label$, value: value$, readonly: true, testId }" [parent]="this"></component-mapper>
|
|
19
|
+
</div>
|
|
20
|
+
</ng-template>
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { RichTextComponent } from './rich-text.component';
|
|
4
|
+
|
|
5
|
+
describe('RichTextComponent', () => {
|
|
6
|
+
let component: RichTextComponent;
|
|
7
|
+
let fixture: ComponentFixture<RichTextComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(waitForAsync(() => {
|
|
10
|
+
TestBed.configureTestingModule({
|
|
11
|
+
declarations: [RichTextComponent]
|
|
12
|
+
}).compileComponents();
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
fixture = TestBed.createComponent(RichTextComponent);
|
|
17
|
+
component = fixture.componentInstance;
|
|
18
|
+
fixture.detectChanges();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should create', () => {
|
|
22
|
+
expect(component).toBeTruthy();
|
|
23
|
+
});
|
|
24
|
+
});
|
package/tests/assets/sdk-a/components/createAll/override-sdk/field/rich-text/rich-text.component.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Component, OnInit, Input, forwardRef, OnDestroy } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormGroup, ReactiveFormsModule } from '@angular/forms';
|
|
4
|
+
import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
|
|
5
|
+
import { Utils } from '@pega/angular-sdk-components';
|
|
6
|
+
import { ComponentMapperComponent } from '@pega/angular-sdk-components';
|
|
7
|
+
import { handleEvent } from '@pega/angular-sdk-components';
|
|
8
|
+
import { PConnFieldProps } from '@pega/angular-sdk-components';
|
|
9
|
+
|
|
10
|
+
interface RichTextProps extends PConnFieldProps {
|
|
11
|
+
// If any, enter additional props that only exist on RichText here
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@Component({
|
|
15
|
+
selector: 'app-rich-text',
|
|
16
|
+
templateUrl: './rich-text.component.html',
|
|
17
|
+
styleUrls: ['./rich-text.component.scss'],
|
|
18
|
+
standalone: true,
|
|
19
|
+
imports: [CommonModule, ReactiveFormsModule, forwardRef(() => ComponentMapperComponent)]
|
|
20
|
+
})
|
|
21
|
+
export class RichTextComponent implements OnInit, OnDestroy {
|
|
22
|
+
@Input() pConn$: typeof PConnect;
|
|
23
|
+
@Input() formGroup$: FormGroup;
|
|
24
|
+
|
|
25
|
+
// Used with AngularPConnect
|
|
26
|
+
angularPConnectData: AngularPConnectData = {};
|
|
27
|
+
configProps$: RichTextProps;
|
|
28
|
+
|
|
29
|
+
label$ = '';
|
|
30
|
+
value$ = '';
|
|
31
|
+
bRequired$ = false;
|
|
32
|
+
bReadonly$ = false;
|
|
33
|
+
bDisabled$ = false;
|
|
34
|
+
bVisible$ = true;
|
|
35
|
+
displayMode$?: string = '';
|
|
36
|
+
controlName$: string;
|
|
37
|
+
testId: string;
|
|
38
|
+
helperText: string;
|
|
39
|
+
placeholder: any;
|
|
40
|
+
info: any;
|
|
41
|
+
error: boolean;
|
|
42
|
+
status: any;
|
|
43
|
+
|
|
44
|
+
constructor(
|
|
45
|
+
private angularPConnect: AngularPConnectService,
|
|
46
|
+
private utils: Utils
|
|
47
|
+
) {}
|
|
48
|
+
|
|
49
|
+
ngOnInit(): void {
|
|
50
|
+
// First thing in initialization is registering and subscribing to the AngularPConnect service
|
|
51
|
+
this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange);
|
|
52
|
+
|
|
53
|
+
// call updateSelf when initializing
|
|
54
|
+
this.checkAndUpdate();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
ngOnDestroy(): void {
|
|
58
|
+
if (this.angularPConnectData.unsubscribeFn) {
|
|
59
|
+
this.angularPConnectData.unsubscribeFn();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Callback passed when subscribing to store change
|
|
64
|
+
onStateChange() {
|
|
65
|
+
this.checkAndUpdate();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
checkAndUpdate() {
|
|
69
|
+
// Should always check the bridge to see if the component should
|
|
70
|
+
// update itself (re-render)
|
|
71
|
+
const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this);
|
|
72
|
+
|
|
73
|
+
// ONLY call updateSelf when the component should update
|
|
74
|
+
if (bUpdateSelf) {
|
|
75
|
+
this.updateSelf();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// updateSelf
|
|
80
|
+
updateSelf(): void {
|
|
81
|
+
// moved this from ngOnInit() and call this from there instead...
|
|
82
|
+
this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as RichTextProps;
|
|
83
|
+
const stateProps: any = this.pConn$.getStateProps();
|
|
84
|
+
this.status = stateProps?.status;
|
|
85
|
+
|
|
86
|
+
if (this.configProps$.value != undefined) {
|
|
87
|
+
this.value$ = this.configProps$.value;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.testId = this.configProps$.testId;
|
|
91
|
+
this.displayMode$ = this.configProps$.displayMode;
|
|
92
|
+
this.label$ = this.configProps$.label;
|
|
93
|
+
this.placeholder = this.configProps$.placeholder;
|
|
94
|
+
this.info = stateProps?.validatemessage || this.configProps$.helperText;
|
|
95
|
+
this.error = stateProps?.status === 'error';
|
|
96
|
+
|
|
97
|
+
if (this.configProps$.required != null) {
|
|
98
|
+
this.bRequired$ = this.utils.getBooleanValue(this.configProps$.required);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (this.configProps$.visibility != null) {
|
|
102
|
+
this.bVisible$ = this.utils.getBooleanValue(this.configProps$.visibility);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (this.configProps$.disabled != undefined) {
|
|
106
|
+
this.bDisabled$ = this.utils.getBooleanValue(this.configProps$.disabled);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (this.configProps$.readOnly != null) {
|
|
110
|
+
this.bReadonly$ = this.utils.getBooleanValue(this.configProps$.readOnly);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
fieldOnChange() {
|
|
115
|
+
if (this.status === 'error') {
|
|
116
|
+
const property = (this.pConn$.getStateProps() as any).value;
|
|
117
|
+
this.pConn$.clearErrorMessages({
|
|
118
|
+
property,
|
|
119
|
+
category: '',
|
|
120
|
+
context: ''
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
fieldOnBlur(editorValue: any) {
|
|
126
|
+
// PConnect wants to use eventHandler for onBlur
|
|
127
|
+
const actionsApi = this.pConn$?.getActionsApi();
|
|
128
|
+
const propName = (this.pConn$?.getStateProps() as any).value;
|
|
129
|
+
handleEvent(actionsApi, 'changeNblur', propName, editorValue);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -149,24 +149,30 @@ export class FileUtilityComponent implements OnInit, OnDestroy {
|
|
|
149
149
|
this.lu_bLoading$ = true;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
attachmentUtils
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
})
|
|
163
|
-
.catch(console.error);
|
|
152
|
+
const arFiles: any = Array.from(files);
|
|
153
|
+
|
|
154
|
+
Promise.allSettled(
|
|
155
|
+
arFiles.map(file => attachmentUtils.uploadAttachment(file, this.onUploadProgress, this.errorHandler, this.pConn$.getContextName()))
|
|
156
|
+
)
|
|
157
|
+
.then((fileResponses: any) => {
|
|
158
|
+
const uploadedFiles: any = [];
|
|
159
|
+
fileResponses.forEach(fileResponse => {
|
|
160
|
+
if (fileResponse.status === 'fulfilled') {
|
|
161
|
+
uploadedFiles.push(fileResponse.value);
|
|
164
162
|
}
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
|
|
163
|
+
});
|
|
164
|
+
if (uploadedFiles.length > 0) {
|
|
165
|
+
(attachmentUtils.linkAttachmentsToCase(caseID, uploadedFiles, 'File', this.pConn$.getContextName()) as Promise<any>)
|
|
166
|
+
.then(() => {
|
|
167
|
+
this.refreshAttachments();
|
|
168
|
+
})
|
|
169
|
+
.catch();
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
.catch();
|
|
168
173
|
|
|
169
174
|
this.arFileList$ = [];
|
|
175
|
+
this.lu_bLoading$ = false;
|
|
170
176
|
}
|
|
171
177
|
|
|
172
178
|
refreshAttachments() {
|
|
@@ -691,9 +697,16 @@ export class FileUtilityComponent implements OnInit, OnDestroy {
|
|
|
691
697
|
if (caseID) {
|
|
692
698
|
this.lu_bLoading$ = true;
|
|
693
699
|
|
|
694
|
-
this.fetchCaseAttachments(caseID)
|
|
695
|
-
|
|
696
|
-
|
|
700
|
+
this.fetchCaseAttachments(caseID)
|
|
701
|
+
.then(resp => {
|
|
702
|
+
this.handleAttachmentsResponse(resp);
|
|
703
|
+
})
|
|
704
|
+
.catch(err => {
|
|
705
|
+
console.log(err);
|
|
706
|
+
})
|
|
707
|
+
.finally(() => {
|
|
708
|
+
this.lu_bLoading$ = false;
|
|
709
|
+
});
|
|
697
710
|
}
|
|
698
711
|
}
|
|
699
712
|
|