@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.
Files changed (50) hide show
  1. package/package.json +1 -1
  2. package/src/constants.js +12 -0
  3. package/src/tasks/create/templates/SDK-React/field/Boolean/index.tsx.mustache +23 -21
  4. package/src/tasks/create/templates/SDK-React/field/Date/index.tsx.mustache +24 -26
  5. package/src/tasks/create/templates/SDK-React/field/DateTime/index.tsx.mustache +20 -22
  6. package/src/tasks/create/templates/SDK-React/field/Decimal/index.tsx.mustache +3 -4
  7. package/src/tasks/create/templates/SDK-React/field/Decimal-Currency/index.tsx.mustache +3 -4
  8. package/src/tasks/create/templates/SDK-React/field/Decimal-Percentage/index.tsx.mustache +3 -4
  9. package/src/tasks/create/templates/SDK-React/field/Integer/index.tsx.mustache +3 -4
  10. package/src/tasks/create/templates/SDK-React/field/Picklist/index.tsx.mustache +3 -4
  11. package/src/tasks/create/templates/SDK-React/field/Picklist-Autocomplete/index.tsx.mustache +31 -32
  12. package/src/tasks/create/templates/SDK-React/field/Picklist-RadioButtons/index.tsx.mustache +22 -23
  13. package/src/tasks/create/templates/SDK-React/field/Text/index.tsx.mustache +18 -19
  14. package/src/tasks/create/templates/SDK-React/field/Text-Email/index.tsx.mustache +26 -27
  15. package/src/tasks/create/templates/SDK-React/field/Text-Input/index.tsx.mustache +18 -19
  16. package/src/tasks/create/templates/SDK-React/field/Text-Paragraph/index.tsx.mustache +21 -22
  17. package/src/tasks/create/templates/SDK-React/field/Text-Phone/index.tsx.mustache +39 -40
  18. package/src/tasks/create/templates/SDK-React/field/Text-URL/index.tsx.mustache +19 -20
  19. package/src/tasks/create/templates/SDK-React/field/TimeOfDay/index.tsx.mustache +4 -5
  20. package/src/tasks/create/templates/SDK-React/template/DETAILS/index.tsx.mustache +19 -20
  21. package/src/tasks/create/templates/SDK-React/template/DETAILS-region/index.tsx.mustache +19 -20
  22. package/src/tasks/create/templates/SDK-React/template/FORM/index.tsx.mustache +6 -7
  23. package/src/tasks/create/templates/SDK-React/template/FORM-region/index.tsx.mustache +8 -9
  24. package/src/tasks/create/templates/SDK-React/template/PAGE/index.tsx.mustache +4 -5
  25. package/src/tasks/create/templates/SDK-React/widget/CASE/index.tsx.mustache +10 -11
  26. package/src/tasks/create/templates/SDK-React/widget/PAGE/index.tsx.mustache +23 -24
  27. package/src/tasks/create/templates/SDK-React/widget/PAGE-CASE/index.tsx.mustache +37 -37
  28. package/src/tasks/validator/index.js +52 -47
  29. package/tests/assets/sdk-a/components/create/override-sdk/designSystemExtension/material-summary-item/material-summary-item.component.html +2 -2
  30. package/tests/assets/sdk-a/components/create/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.html +33 -0
  31. package/tests/assets/sdk-a/components/create/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.scss +19 -0
  32. package/tests/assets/sdk-a/components/create/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.spec.ts +24 -0
  33. package/tests/assets/sdk-a/components/create/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.ts +89 -0
  34. package/tests/assets/sdk-a/components/create/override-sdk/field/dropdown/dropdown.component.ts +1 -1
  35. package/tests/assets/sdk-a/components/create/override-sdk/field/rich-text/rich-text.component.html +20 -0
  36. package/tests/assets/sdk-a/components/create/override-sdk/field/rich-text/rich-text.component.scss +0 -0
  37. package/tests/assets/sdk-a/components/create/override-sdk/field/rich-text/rich-text.component.spec.ts +24 -0
  38. package/tests/assets/sdk-a/components/create/override-sdk/field/rich-text/rich-text.component.ts +131 -0
  39. package/tests/assets/sdk-a/components/create/override-sdk/widget/file-utility/file-utility.component.ts +31 -18
  40. package/tests/assets/sdk-a/components/createAll/override-sdk/designSystemExtension/material-summary-item/material-summary-item.component.html +2 -2
  41. package/tests/assets/sdk-a/components/createAll/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.html +33 -0
  42. package/tests/assets/sdk-a/components/createAll/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.scss +19 -0
  43. package/tests/assets/sdk-a/components/createAll/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.spec.ts +24 -0
  44. package/tests/assets/sdk-a/components/createAll/override-sdk/designSystemExtension/rich-text-editor/rich-text-editor.component.ts +89 -0
  45. package/tests/assets/sdk-a/components/createAll/override-sdk/field/dropdown/dropdown.component.ts +1 -1
  46. package/tests/assets/sdk-a/components/createAll/override-sdk/field/rich-text/rich-text.component.html +20 -0
  47. package/tests/assets/sdk-a/components/createAll/override-sdk/field/rich-text/rich-text.component.scss +0 -0
  48. package/tests/assets/sdk-a/components/createAll/override-sdk/field/rich-text/rich-text.component.spec.ts +24 -0
  49. package/tests/assets/sdk-a/components/createAll/override-sdk/field/rich-text/rich-text.component.ts +131 -0
  50. package/tests/assets/sdk-a/components/createAll/override-sdk/widget/file-utility/file-utility.component.ts +31 -18
@@ -13,13 +13,13 @@ import { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
13
13
 
14
14
  interface {{COMPONENT_CLASS_NAME}}Props extends PConnProps {
15
15
  // If any, enter additional props that only exist on this component
16
- label: string;
17
- createDateTime: string;
18
- createLabel: string;
19
- createOperator: { userName: string; userId: string };
20
- updateDateTime: string;
21
- updateLabel: string;
22
- updateOperator: { userName: string; userId: string };
16
+ label: string;
17
+ createDateTime: string;
18
+ createLabel: string;
19
+ createOperator: { userName: string; userId: string };
20
+ updateDateTime: string;
21
+ updateLabel: string;
22
+ updateOperator: { userName: string; userId: string };
23
23
  }
24
24
 
25
25
  const useStyles = makeStyles(theme => ({
@@ -38,7 +38,6 @@ const useStyles = makeStyles(theme => ({
38
38
  // Page Case Widget example
39
39
 
40
40
  // props passed in combination of props from property panel (config.json) and run time props from Constellation
41
- // any default values in config.pros should be set in defaultProps at bottom of this file
42
41
  export default function {{COMPONENT_CLASS_NAME}}(props: {{COMPONENT_CLASS_NAME}}Props) {
43
42
  // const componentName = "Operator";
44
43
  const classes = useStyles();
@@ -192,37 +191,38 @@ export default function {{COMPONENT_CLASS_NAME}}(props: {{COMPONENT_CLASS_NAME}}
192
191
  // End of popover-related
193
192
 
194
193
  return (
195
- <Styled{{COMPONENT_CLASS_NAME}}Wrapper><>
196
- {{! pick new delimiters for mustache }}
197
- {{=<% %>=}}
198
- <TextField
199
- defaultValue={caseOpName}
200
- label={caseOpLabel}
201
- onClick={showOperatorDetails}
202
- InputProps={{
203
- readOnly: true,
204
- disableUnderline: true,
205
- inputProps: { style: { cursor: 'pointer' } }
206
- }}
207
- />
208
- <br />
209
- {Utils.generateDateTime(caseTime, 'DateTime-Since')}
210
- <%={{ }}=%> {{! revert delimiters for mustache }}
211
- <Popover
212
- id={popoverId}
213
- open={popoverOpen}
214
- anchorEl={popoverAnchorEl}
215
- onClose={handlePopoverClose}
194
+ <Styled{{COMPONENT_CLASS_NAME}}Wrapper>
195
+ <>
216
196
  {{! pick new delimiters for mustache }}
217
197
  {{=<% %>=}}
218
- anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
219
- transformOrigin={{ vertical: 'top', horizontal: 'center' }}
220
- PaperProps={{ style: { maxWidth: '45ch' } }}
198
+ <TextField
199
+ defaultValue={caseOpName}
200
+ label={caseOpLabel}
201
+ onClick={showOperatorDetails}
202
+ InputProps={{
203
+ readOnly: true,
204
+ disableUnderline: true,
205
+ inputProps: { style: { cursor: 'pointer' } }
206
+ }}
207
+ />
208
+ <br />
209
+ {Utils.generateDateTime(caseTime, 'DateTime-Since')}
221
210
  <%={{ }}=%> {{! revert delimiters for mustache }}
222
- >
223
- {getPopoverGrid()}
224
- </Popover>
225
- </>
211
+ <Popover
212
+ id={popoverId}
213
+ open={popoverOpen}
214
+ anchorEl={popoverAnchorEl}
215
+ onClose={handlePopoverClose}
216
+ {{! pick new delimiters for mustache }}
217
+ {{=<% %>=}}
218
+ anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
219
+ transformOrigin={{ vertical: 'top', horizontal: 'center' }}
220
+ PaperProps={{ style: { maxWidth: '45ch' } }}
221
+ <%={{ }}=%> {{! revert delimiters for mustache }}
222
+ >
223
+ {getPopoverGrid()}
224
+ </Popover>
225
+ </>
226
226
  </Styled{{COMPONENT_CLASS_NAME}}Wrapper>
227
227
  );
228
- }
228
+ }
@@ -5,22 +5,19 @@ import chalk from 'chalk';
5
5
  import inquirer from 'inquirer';
6
6
  import Ajv from 'ajv';
7
7
 
8
- import {
9
- COMPONENT_SCHEMA,
10
- CATEGORY_CUSTOM,
11
- CATEGORY_OVERRIDE } from '../../constants.js';
12
-
8
+ import { COMPONENT_SCHEMA, CATEGORY_CUSTOM, CATEGORY_OVERRIDE } from '../../constants.js';
13
9
  import {
14
10
  getComponentDirectoryPath,
15
11
  getComponents,
16
12
  getOOTBComponents,
17
13
  removeComponentPrefix,
18
- getFramework,
19
- getLocalComponentKeyFromConfig} from '../../util.js';
14
+ getFramework,
15
+ getLocalComponentKeyFromConfig
16
+ } from '../../util.js';
20
17
 
21
18
  const ajv = new Ajv({ allErrors: true });
22
19
 
23
- const combinationTypes = ['PAGE', 'CASE'];
20
+ // const combinationTypes = ['PAGE', 'CASE'];
24
21
 
25
22
  const allowedSubtypes = [
26
23
  ...new Set([
@@ -30,13 +27,25 @@ const allowedSubtypes = [
30
27
  ])
31
28
  ];
32
29
 
30
+ const allowedOverrideTypes = [
31
+ ...new Set([...COMPONENT_SCHEMA.type.map(({ value }) => value)]),
32
+ 'Group'
33
+ ];
34
+
33
35
  // additional subtypes are manually added below
34
36
  const allowedOverrideSubtypes = [
35
37
  ...new Set([
36
38
  ...COMPONENT_SCHEMA.subtype.field.map(({ value }) => value),
37
39
  ...COMPONENT_SCHEMA.subtype.template.map(({ value }) => value),
38
40
  ...COMPONENT_SCHEMA.subtype.widget.map(({ value }) => value)
39
- ]), "ACTION", "DATA_CAPTURE", "SUMMARY", "CASEVIEW", "DATAVIEW", "LIST", "TAB"
41
+ ]),
42
+ 'ACTION',
43
+ 'DATA_CAPTURE',
44
+ 'SUMMARY',
45
+ 'CASEVIEW',
46
+ 'DATAVIEW',
47
+ 'LIST',
48
+ 'TAB'
40
49
  ];
41
50
 
42
51
  const schema = {
@@ -93,16 +102,16 @@ const schema = {
93
102
  {
94
103
  type: 'object',
95
104
  properties: {
96
- key: { type: 'string'},
105
+ key: { type: 'string' },
97
106
  name: { type: 'string' },
98
107
  label: { type: 'string' },
99
108
  format: { type: 'string' }
100
109
  },
101
- required: ['key','name', 'label', 'format']
110
+ required: ['key', 'name', 'label', 'format']
102
111
  }
103
112
  ]
104
113
  }
105
- },
114
+ }
106
115
  },
107
116
  required: ['format']
108
117
  },
@@ -159,13 +168,12 @@ const schema = {
159
168
  }
160
169
  },
161
170
  required: ['format', 'elements']
162
- },
171
+ }
163
172
  ]
164
173
  }
165
174
  }
166
-
167
175
  },
168
- required: ['label', 'format'],
176
+ required: ['label', 'format']
169
177
  }
170
178
  ]
171
179
  }
@@ -188,7 +196,7 @@ const overrideSchema = {
188
196
  version: { type: 'string' },
189
197
  library: { type: 'string' },
190
198
  allowedApplications: { type: 'array' },
191
- type: { type: 'string', enum: COMPONENT_SCHEMA.type.map(({ value }) => value) },
199
+ type: { type: 'string', enum: allowedOverrideTypes },
192
200
  subtype: {
193
201
  anyOf: [{ type: 'string' }, { type: 'array' }],
194
202
 
@@ -230,16 +238,16 @@ const overrideSchema = {
230
238
  {
231
239
  type: 'object',
232
240
  properties: {
233
- key: { type: 'string'},
241
+ key: { type: 'string' },
234
242
  name: { type: 'string' },
235
243
  label: { type: 'string' },
236
244
  format: { type: 'string' }
237
245
  },
238
- required: ['key','name', 'label', 'format']
246
+ required: ['key', 'name', 'label', 'format']
239
247
  }
240
248
  ]
241
249
  }
242
- },
250
+ }
243
251
  },
244
252
  required: ['format']
245
253
  },
@@ -296,13 +304,12 @@ const overrideSchema = {
296
304
  }
297
305
  },
298
306
  required: ['format', 'elements']
299
- },
307
+ }
300
308
  ]
301
309
  }
302
310
  }
303
-
304
311
  },
305
- required: ['label', 'format'],
312
+ required: ['label', 'format']
306
313
  }
307
314
  ]
308
315
  }
@@ -316,8 +323,6 @@ const overrideSchema = {
316
323
  const validateSchema = ajv.compile(schema);
317
324
  const validateOverrideSchema = ajv.compile(overrideSchema);
318
325
 
319
-
320
-
321
326
  export default async (option, category = CATEGORY_CUSTOM) => {
322
327
  let componentToValidate = null;
323
328
  const framework = await getFramework();
@@ -341,55 +346,57 @@ export default async (option, category = CATEGORY_CUSTOM) => {
341
346
  }
342
347
 
343
348
  const componentDirectory = await getComponentDirectoryPath(componentToValidate, category);
344
- let configFileName = "config.json";
349
+ let configFileName = 'config.json';
345
350
  if (category === CATEGORY_OVERRIDE) {
346
- configFileName = "config-ext.json";
351
+ configFileName = 'config-ext.json';
347
352
  }
348
353
  const configFile = path.join(componentDirectory, configFileName);
349
354
  let configData;
350
355
  try {
351
356
  configData = fs.readFileSync(path.resolve(configFile), 'utf8');
352
- }
353
- catch (err) {
357
+ } catch (err) {
354
358
  if (category === CATEGORY_CUSTOM) {
355
359
  throw new Error(`Missing config file for: ${componentToValidate}`);
356
- }
357
- else if (category === CATEGORY_OVERRIDE) {
360
+ } else if (category === CATEGORY_OVERRIDE) {
358
361
  // for now, if now file just end
359
- console.log(`${chalk.bold.yellow('Config file not available for: ' + componentToValidate)}`);
362
+ console.log(`${chalk.bold.yellow(`Config file not available for: ${componentToValidate}`)}`);
360
363
  return;
361
364
  }
362
365
  }
363
366
 
364
- //const data = JSON.parse(fs.readFileSync(path.resolve(configFile), 'utf8'));
367
+ // const data = JSON.parse(fs.readFileSync(path.resolve(configFile), 'utf8'));
365
368
  const data = JSON.parse(configData);
366
369
 
367
- // for now a special case for ScalarList, it doesn't have a "subtype", so for now manualy
370
+ // for now a special case for ScalarList & Group, those doesn't have a "subtype", so for now manualy
368
371
  // add one in here, just to pass validation
369
- if (data["name"] === "ScalarList") {
370
- data["subtype"] = "LIST";
372
+ if (data.name === 'ScalarList') {
373
+ data.subtype = 'LIST';
374
+ }
375
+ if (data.name === 'Group') {
376
+ data.subtype = 'DATA_CAPTURE';
371
377
  }
372
378
 
373
- const valid = (category === CATEGORY_OVERRIDE) ? validateOverrideSchema(data) : validateSchema(data);
379
+ const valid =
380
+ category === CATEGORY_OVERRIDE ? validateOverrideSchema(data) : validateSchema(data);
374
381
 
375
382
  if (valid) {
376
-
377
383
  // need to remove path
378
384
  const originalComponentToValidate = componentToValidate;
379
385
  componentToValidate = removeComponentPrefix(componentToValidate);
380
386
 
381
387
  // don't check for out the box if override
382
- if (category != CATEGORY_OVERRIDE) {
383
-
388
+ if (category !== CATEGORY_OVERRIDE) {
384
389
  // we are validating the component name, not the actual component
385
390
  // so need to get the component name (or key) from config.json
386
- switch(framework) {
387
- case "SDK-Angular":
391
+ switch (framework) {
392
+ case 'SDK-Angular':
388
393
  componentToValidate = await getLocalComponentKeyFromConfig(originalComponentToValidate);
389
394
  break;
390
- case "SDK-React":
395
+ case 'SDK-React':
396
+ break;
397
+ case 'SDK-WebComponents':
391
398
  break;
392
- case "SDK-WebComponents":
399
+ default:
393
400
  break;
394
401
  }
395
402
 
@@ -404,15 +411,13 @@ export default async (option, category = CATEGORY_CUSTOM) => {
404
411
  }
405
412
  }
406
413
 
407
-
408
414
  console.log(`${chalk.bold.green(componentToValidate)} schema is valid`);
409
415
  } else {
416
+ // eslint-disable-next-line no-lonely-if
410
417
  if (category === CATEGORY_OVERRIDE) {
411
418
  throw new Error(`Invalid: ${ajv.errorsText(validateOverrideSchema.errors)}`);
412
- }
413
- else {
419
+ } else {
414
420
  throw new Error(`Invalid: ${ajv.errorsText(validateSchema.errors)}`);
415
421
  }
416
-
417
422
  }
418
423
  };
@@ -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
+ }
@@ -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>
@@ -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
+ });