@pega/dx-component-builder-sdk 0.23.21 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +1 -1
  3. package/src/constants.js +4 -0
  4. package/src/tasks/build-all/helper.js +6 -0
  5. package/src/tasks/build-comp/helper.js +6 -0
  6. package/src/tasks/bundle/builderAngular/webpack.config.js +14 -1
  7. package/src/tasks/bundle/builderAssociated/webpack.config.js +13 -0
  8. package/src/tasks/bundle/builderReact/webpack.config.js +14 -1
  9. package/src/tasks/create/templates/Constellation/field/Boolean/index.tsx.mustache +3 -2
  10. package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/PConnProps.d.ts.mustache +46 -0
  11. package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/config.json.mustache +64 -0
  12. package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/demo.stories.tsx.mustache +99 -0
  13. package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/index.tsx.mustache +204 -0
  14. package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/mock.ts.mustache +5 -0
  15. package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/styles.ts.mustache +8 -0
  16. package/src/tasks/create/templates/Constellation/field/Picklist-Autocomplete/index.tsx.mustache +11 -0
  17. package/src/tasks/create/templates/Constellation/field/Picklist-Autocomplete/utils.ts.mustache +3 -0
  18. package/src/tasks/create/templates/Constellation/field/Text/index.tsx.mustache +94 -4
  19. package/src/tasks/create/templates/Constellation/template/DETAILS/Avatar.tsx.mustache +78 -0
  20. package/src/tasks/create/templates/Constellation/template/DETAILS/DetailsRender.tsx.mustache +55 -0
  21. package/src/tasks/create/templates/Constellation/template/DETAILS/HighlightRender.tsx.mustache +49 -0
  22. package/src/tasks/create/templates/Constellation/template/DETAILS/Operator.tsx.mustache +218 -0
  23. package/src/tasks/create/templates/Constellation/template/DETAILS/demo.stories.tsx.mustache +77 -23
  24. package/src/tasks/create/templates/Constellation/template/DETAILS/index.tsx.mustache +51 -40
  25. package/src/tasks/create/templates/Constellation/template/DETAILS/mock.ts.mustache +78 -20
  26. package/src/tasks/create/templates/Constellation/template/DETAILS/styles.ts.mustache +16 -0
  27. package/src/tasks/create/templates/Constellation/template/DETAILS-region/Avatar.tsx.mustache +78 -0
  28. package/src/tasks/create/templates/Constellation/template/DETAILS-region/DetailsRender.tsx.mustache +55 -0
  29. package/src/tasks/create/templates/Constellation/template/DETAILS-region/HighlightRender.tsx.mustache +49 -0
  30. package/src/tasks/create/templates/Constellation/template/DETAILS-region/Operator.tsx.mustache +218 -0
  31. package/src/tasks/create/templates/Constellation/template/DETAILS-region/demo.stories.tsx.mustache +95 -26
  32. package/src/tasks/create/templates/Constellation/template/DETAILS-region/index.tsx.mustache +43 -40
  33. package/src/tasks/create/templates/Constellation/template/DETAILS-region/mock.ts.mustache +68 -10
  34. package/src/tasks/create/templates/Constellation/template/DETAILS-region/styles.ts.mustache +15 -0
  35. package/src/tasks/create/templates/Constellation/template/FORM/DetailsRender.tsx +59 -0
  36. package/src/tasks/create/templates/Constellation/template/FORM/index.tsx.mustache +31 -5
  37. package/src/tasks/create/templates/Constellation/template/FORM-region/DetailsRender.tsx +59 -0
  38. package/src/tasks/create/templates/Constellation/template/FORM-region/index.tsx.mustache +29 -7
  39. package/src/tasks/create/templates/Constellation/template/PAGE/GetNextWork.tsx.mustache +2 -1
  40. package/src/tasks/create/templates/Constellation/template/PAGE/localizations.json.mustache +4 -2
  41. package/src/tasks/create/templates/Constellation/widget/PAGE/demo.stories.tsx.mustache +87 -6
  42. package/src/tasks/create/templates/Constellation/widget/PAGE/index.tsx.mustache +67 -5
  43. package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/config.json.mustache +64 -0
  44. package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/demo.stories.tsx.mustache +42 -0
  45. package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/mock.ts.mustache +17 -0
  46. package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/text-url.component.html.mustache +29 -0
  47. package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/text-url.component.scss.mustache +20 -0
  48. package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/text-url.component.spec.ts.mustache +26 -0
  49. package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/text-url.component.ts.mustache +179 -0
  50. package/src/tasks/create/templates/SDK-React/field/Icon-Button-URL/config.json.mustache +64 -0
  51. package/src/tasks/create/templates/SDK-React/field/Icon-Button-URL/demo.stories.tsx.mustache +58 -0
  52. package/src/tasks/create/templates/SDK-React/field/Icon-Button-URL/index.tsx.mustache +79 -0
  53. package/src/tasks/create/templates/SDK-React/field/Icon-Button-URL/mock.ts.mustache +16 -0
  54. package/src/tasks/create/templates/SDK-React/field/Icon-Button-URL/styles.js.mustache +7 -0
  55. package/src/tasks/create/templates/SDK-React/template/DETAILS/demo.stories.tsx.mustache +0 -3
  56. package/src/tasks/create/templates/SDK-React/template/DETAILS/index.tsx.mustache +1 -1
  57. package/src/tasks/create/templates/SDK-React/template/DETAILS-region/demo.stories.tsx.mustache +0 -3
  58. package/src/tasks/create/templates/SDK-React/template/DETAILS-region/index.tsx.mustache +1 -1
  59. package/src/tasks/create-all/index.js +3 -0
  60. package/src/tasks/publish/helper.js +4 -0
  61. package/src/tasks/publish-all/helper.js +6 -2
  62. package/src/tasks/validator/index.js +7 -1
@@ -0,0 +1,26 @@
1
+
2
+ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
3
+
4
+ import { {{COMPONENT_CLASS_NAME}}Component } from './{{COMPONENT_CLASS_NAME_KEBAB}}.component';
5
+
6
+ describe('{{COMPONENT_CLASS_NAME}}Component', () => {
7
+ let component: {{COMPONENT_CLASS_NAME}}Component;
8
+ let fixture: ComponentFixture<{{COMPONENT_CLASS_NAME}}Component>;
9
+
10
+ beforeEach(waitForAsync(() => {
11
+ TestBed.configureTestingModule({
12
+ declarations: [ {{COMPONENT_CLASS_NAME}}Component ]
13
+ })
14
+ .compileComponents();
15
+ }));
16
+
17
+ beforeEach(() => {
18
+ fixture = TestBed.createComponent({{COMPONENT_CLASS_NAME}}Component);
19
+ component = fixture.componentInstance;
20
+ fixture.detectChanges();
21
+ });
22
+
23
+ it('should create', () => {
24
+ expect(component).toBeTruthy();
25
+ });
26
+ });
@@ -0,0 +1,179 @@
1
+ import { Component, OnInit, Input, ChangeDetectorRef, forwardRef, OnDestroy } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
4
+ import { MatInputModule } from '@angular/material/input';
5
+ import { MatFormFieldModule } from '@angular/material/form-field';
6
+ import { interval } from 'rxjs';
7
+ import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
8
+ import { Utils } from '@pega/angular-sdk-components';
9
+ import { ComponentMapperComponent } from '@pega/angular-sdk-components';
10
+ import { PConnFieldProps } from '@pega/angular-sdk-components';
11
+
12
+ interface {{COMPONENT_CLASS_NAME}}Props extends PConnFieldProps {
13
+ // If any, enter additional props that only exist on URL here
14
+ }
15
+
16
+ @Component({
17
+ selector: 'app-{{COMPONENT_CLASS_NAME_KEBAB}}',
18
+ templateUrl: './{{COMPONENT_CLASS_NAME_KEBAB}}.component.html',
19
+ styleUrls: ['./{{COMPONENT_CLASS_NAME_KEBAB}}.component.scss'],
20
+ standalone: true,
21
+ imports: [CommonModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, forwardRef(() => ComponentMapperComponent)]
22
+ })
23
+ export class {{COMPONENT_CLASS_NAME}}Component implements OnInit, OnDestroy {
24
+ @Input() pConn$: typeof PConnect;
25
+ @Input() formGroup$: FormGroup;
26
+
27
+ // Used with AngularPConnect
28
+ angularPConnectData: AngularPConnectData = {};
29
+ configProps$: {{COMPONENT_CLASS_NAME}}Props;
30
+
31
+ label$ = '';
32
+ value$ = '';
33
+ bRequired$ = false;
34
+ bReadonly$ = false;
35
+ bDisabled$ = false;
36
+ bVisible$ = true;
37
+ displayMode$?: string = '';
38
+ controlName$: string;
39
+ bHasForm$ = true;
40
+ componentReference = '';
41
+ helperText: string;
42
+ placeholder: string;
43
+
44
+ fieldControl = new FormControl('', null);
45
+
46
+ constructor(
47
+ private angularPConnect: AngularPConnectService,
48
+ private cdRef: ChangeDetectorRef,
49
+ private utils: Utils
50
+ ) {}
51
+
52
+ ngOnInit(): void {
53
+ // First thing in initialization is registering and subscribing to the AngularPConnect service
54
+ this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange);
55
+ this.controlName$ = this.angularPConnect.getComponentID(this);
56
+
57
+ // Then, continue on with other initialization
58
+
59
+ // call updateSelf when initializing
60
+ // this.updateSelf();
61
+ this.checkAndUpdate();
62
+
63
+ if (this.formGroup$) {
64
+ // add control to formGroup
65
+ this.formGroup$.addControl(this.controlName$, this.fieldControl);
66
+ this.fieldControl.setValue(this.value$);
67
+ this.bHasForm$ = true;
68
+ } else {
69
+ this.bReadonly$ = true;
70
+ this.bHasForm$ = false;
71
+ }
72
+ }
73
+
74
+ ngOnDestroy(): void {
75
+ if (this.formGroup$) {
76
+ this.formGroup$.removeControl(this.controlName$);
77
+ }
78
+
79
+ if (this.angularPConnectData.unsubscribeFn) {
80
+ this.angularPConnectData.unsubscribeFn();
81
+ }
82
+ }
83
+
84
+ // Callback passed when subscribing to store change
85
+ onStateChange() {
86
+ this.checkAndUpdate();
87
+ }
88
+
89
+ checkAndUpdate() {
90
+ // Should always check the bridge to see if the component should
91
+ // update itself (re-render)
92
+ const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this);
93
+
94
+ // ONLY call updateSelf when the component should update
95
+ if (bUpdateSelf) {
96
+ this.updateSelf();
97
+ }
98
+ }
99
+
100
+ // updateSelf
101
+ updateSelf(): void {
102
+ // moved this from ngOnInit() and call this from there instead...
103
+ this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as {{COMPONENT_CLASS_NAME}}Props;
104
+
105
+ if (this.configProps$.value != undefined) {
106
+ this.value$ = this.configProps$.value;
107
+ }
108
+
109
+ this.label$ = this.configProps$.label;
110
+ this.displayMode$ = this.configProps$.displayMode;
111
+ this.helperText = this.configProps$.helperText;
112
+ this.placeholder = this.configProps$.placeholder || '';
113
+
114
+ // timeout and detectChanges to avoid ExpressionChangedAfterItHasBeenCheckedError
115
+ setTimeout(() => {
116
+ if (this.configProps$.required != null) {
117
+ this.bRequired$ = this.utils.getBooleanValue(this.configProps$.required);
118
+ }
119
+ this.cdRef.detectChanges();
120
+ });
121
+
122
+ if (this.configProps$.visibility != null) {
123
+ this.bVisible$ = this.utils.getBooleanValue(this.configProps$.visibility);
124
+ }
125
+
126
+ // disabled
127
+ if (this.configProps$.disabled != undefined) {
128
+ this.bDisabled$ = this.utils.getBooleanValue(this.configProps$.disabled);
129
+ }
130
+
131
+ if (this.bDisabled$) {
132
+ this.fieldControl.disable();
133
+ } else {
134
+ this.fieldControl.enable();
135
+ }
136
+
137
+ if (this.configProps$.readOnly != null) {
138
+ this.bReadonly$ = this.utils.getBooleanValue(this.configProps$.readOnly);
139
+ }
140
+
141
+ this.componentReference = (this.pConn$.getStateProps() as any).value;
142
+
143
+ // trigger display of error message with field control
144
+ if (this.angularPConnectData.validateMessage != null && this.angularPConnectData.validateMessage != '') {
145
+ const timer = interval(100).subscribe(() => {
146
+ this.fieldControl.setErrors({ message: true });
147
+ this.fieldControl.markAsTouched();
148
+
149
+ timer.unsubscribe();
150
+ });
151
+ }
152
+ }
153
+
154
+ fieldOnChange(event: any) {
155
+ this.angularPConnectData.actions?.onChange(this, event);
156
+ }
157
+
158
+ fieldOnBlur(event: any) {
159
+ // PConnect wants to use eventHandler for onBlur
160
+ this.angularPConnectData.actions?.onBlur(this, event);
161
+ }
162
+
163
+ getErrorMessage() {
164
+ let errMessage = '';
165
+
166
+ // look for validation messages for json, pre-defined or just an error pushed from workitem (400)
167
+ if (this.fieldControl.hasError('message')) {
168
+ errMessage = this.angularPConnectData.validateMessage ?? '';
169
+ return errMessage;
170
+ }
171
+ if (this.fieldControl.hasError('required')) {
172
+ errMessage = 'You must enter a value';
173
+ } else if (this.fieldControl.errors) {
174
+ errMessage = this.fieldControl.errors.toString();
175
+ }
176
+
177
+ return errMessage;
178
+ }
179
+ }
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "{{COMPONENT_KEY}}",
3
+ "label": "{{COMPONENT_LABEL}}",
4
+ "description": "{{DESCRIPTION}}",
5
+ "organization": "{{ORGANIZATION}}",
6
+ "version": "{{VERSION}}",
7
+ "library": "{{LIBRARY}}",
8
+ "allowedApplications": {{{ALLOWEDAPPS}}},
9
+ "componentKey": "{{COMPONENT_KEY}}",
10
+ "type": "{{TYPE}}",
11
+ "subtype": {{{SUB_TYPE}}},
12
+ "icon": "images/pz-url-active.svg",
13
+ "properties": [
14
+ {
15
+ "format": "SELECT",
16
+ "name": "countryCode",
17
+ "label": "Country code",
18
+ "defaultValue": "USA",
19
+ "source": [
20
+ {
21
+ "key": "USA",
22
+ "value": "United States"
23
+ },
24
+ {
25
+ "key": "CAN",
26
+ "value": "Canada"
27
+ },
28
+ {
29
+ "key": "AUS",
30
+ "value": "Australia"
31
+ },
32
+ {
33
+ "key": "JPN",
34
+ "value": "Japan"
35
+ },
36
+ {
37
+ "key": "IND",
38
+ "value": "India"
39
+ },
40
+ {
41
+ "key": "TUR",
42
+ "value": "Turkey"
43
+ }
44
+ ]
45
+ },
46
+ {
47
+ "label": "Advanced",
48
+ "format": "GROUP",
49
+ "collapsible": true,
50
+ "properties": [
51
+ {
52
+ "name": "testId",
53
+ "label": "Test ID",
54
+ "format": "TEXT",
55
+ "ignorePattern": "[^-_\\p{N}\\p{L}]",
56
+ "includeAnnotations": false
57
+ }
58
+ ]
59
+ }
60
+ ],
61
+ "defaultConfig": {
62
+ "label": "@L $this.label"
63
+ }
64
+ }
@@ -0,0 +1,58 @@
1
+ import { useState } from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+
4
+ import {{COMPONENT_CLASS_NAME}} from './index';
5
+ import { configProps } from './mock';
6
+
7
+ const meta: Meta<typeof {{COMPONENT_CLASS_NAME}}> = {
8
+ title: '{{COMPONENT_CLASS_NAME}}',
9
+ component: {{COMPONENT_CLASS_NAME}},
10
+ excludeStories: /.*Data$/
11
+ };
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof {{COMPONENT_CLASS_NAME}}>;
15
+
16
+ export const Base{{COMPONENT_CLASS_NAME}}: Story = args => {
17
+ const [value, setValue] = useState(configProps.value);
18
+
19
+ const props = {
20
+ value,
21
+ placeholder: configProps.placeholder,
22
+ getPConnect: () => {
23
+ return {
24
+ getActionsApi: () => {
25
+ return {
26
+ updateFieldValue: (propName, theValue) => {
27
+ setValue(theValue);
28
+ }
29
+ };
30
+ },
31
+ getStateProps: () => {
32
+ return { value: '.name' };
33
+ }
34
+ };
35
+ },
36
+ onChange: event => {
37
+ setValue(event.target.value);
38
+ },
39
+ onBlur: () => {
40
+ return configProps.value;
41
+ }
42
+ };
43
+
44
+ return <{{COMPONENT_CLASS_NAME}} {...props} {...args} />;
45
+ };
46
+
47
+ Base{{COMPONENT_CLASS_NAME}}.args = {
48
+ label: configProps.label,
49
+ helperText: configProps.helperText,
50
+ testId: configProps.testId,
51
+ readOnly: configProps.readOnly,
52
+ disabled: configProps.disabled,
53
+ required: configProps.required,
54
+ status: configProps.status,
55
+ hideLabel: configProps.hideLabel,
56
+ displayMode: configProps.displayMode,
57
+ validatemessage: configProps.validatemessage
58
+ };
@@ -0,0 +1,79 @@
1
+ import { TextField } from '@material-ui/core';
2
+
3
+ import { getComponentFromMap } from '@pega/react-sdk-components/lib/bridge/helpers/sdk_component_map';
4
+ import { PConnFieldProps } from '@pega/react-sdk-components/lib/types/PConnProps';
5
+ import Styled{{COMPONENT_CLASS_NAME}}Wrapper from './styles';
6
+
7
+ interface {{COMPONENT_CLASS_NAME}}Props extends PConnFieldProps {
8
+ // If any, enter additional props that only exist on this componentName
9
+ }
10
+
11
+ // Duplicated runtime code from React SDK
12
+
13
+ // props passed in combination of props from property panel (config.json) and run time props from Constellation
14
+ export default function {{COMPONENT_CLASS_NAME}}(props: {{COMPONENT_CLASS_NAME}}Props) {
15
+ // Get emitted components from map (so we can get any override that may exist)
16
+ const FieldValueList = getComponentFromMap('FieldValueList');
17
+ const TextInput = getComponentFromMap('TextInput');
18
+
19
+ const {
20
+ label,
21
+ required,
22
+ disabled,
23
+ value = '',
24
+ validatemessage,
25
+ status,
26
+ onChange,
27
+ onBlur,
28
+ readOnly,
29
+ testId,
30
+ helperText,
31
+ displayMode,
32
+ hideLabel,
33
+ placeholder
34
+ } = props;
35
+ const helperTextToDisplay = validatemessage || helperText;
36
+
37
+ if (displayMode === 'LABELS_LEFT') {
38
+ return <FieldValueList name={hideLabel ? '' : label} value={value} />;
39
+ }
40
+
41
+ if (displayMode === 'STACKED_LARGE_VAL') {
42
+ return <FieldValueList name={hideLabel ? '' : label} value={value} variant='stacked' />;
43
+ }
44
+
45
+ if (readOnly) {
46
+ return <TextInput {...props} />;
47
+ }
48
+
49
+ let testProp = {};
50
+
51
+ testProp = {
52
+ 'data-test-id': testId
53
+ };
54
+
55
+ return (
56
+ <Styled{{COMPONENT_CLASS_NAME}}Wrapper>
57
+ <TextField
58
+ type='url'
59
+ fullWidth
60
+ variant='outlined'
61
+ helperText={helperTextToDisplay}
62
+ placeholder={placeholder ?? ''}
63
+ size='small'
64
+ required={required}
65
+ disabled={disabled}
66
+ onChange={onChange}
67
+ onBlur={!readOnly ? onBlur : undefined}
68
+ error={status === 'error'}
69
+ label={label}
70
+ value={value}
71
+ {{! pick new delimiters for mustache }}
72
+ {{=<% %>=}}
73
+ InputProps={{ inputProps: { ...testProp } }}
74
+ <%={{ }}=%> {{! revert delimiters for mustache }}
75
+ />
76
+ </Styled{{COMPONENT_CLASS_NAME}}Wrapper>
77
+ );
78
+ }
79
+
@@ -0,0 +1,16 @@
1
+ // eslint-disable-next-line import/prefer-default-export
2
+ export const configProps = {
3
+ value: '',
4
+ label: 'URL Sample',
5
+ placeholder: 'URL Placeholder',
6
+ helperText: 'URL Helper Text',
7
+ testId: 'url-12345678',
8
+ hasSuggestions: false,
9
+ required: false,
10
+ disabled: false,
11
+ readOnly: false,
12
+ displayMode: '',
13
+ status: '',
14
+ hideLabel: false,
15
+ validatemessage: ''
16
+ };
@@ -0,0 +1,7 @@
1
+ import styled, { css } from 'styled-components';
2
+
3
+ export default styled.div(() => {
4
+ return css`
5
+ margin: 0px 0;
6
+ `;
7
+ });
@@ -70,9 +70,6 @@ export const Base{{COMPONENT_CLASS_NAME}}: Story = args => {
70
70
  },
71
71
  resolveConfigProps: () => {
72
72
  /* nothing */
73
- },
74
- createComponent: () => {
75
- /* nothing */
76
73
  }
77
74
  };
78
75
  }
@@ -49,7 +49,7 @@ export default function {{COMPONENT_CLASS_NAME}}(props: {{COMPONENT_CLASS_NAME}}
49
49
  field.config.displayAsStatus = true;
50
50
  }
51
51
 
52
- return getPConnect().createComponent(field, '', '', {}); // 2nd, 3rd, and 4th args empty string/object/null until typedef marked correctly as optional
52
+ return getPConnect().createComponent(field, '', 0, {}); // 2nd, 3rd, and 4th args empty string/object/null until typedef marked correctly as optional
53
53
  });
54
54
  }
55
55
 
@@ -68,9 +68,6 @@ export const Base{{COMPONENT_CLASS_NAME}}: Story = args => {
68
68
  },
69
69
  resolveConfigProps: () => {
70
70
  /* nothing */
71
- },
72
- createComponent: () => {
73
- /* nothing */
74
71
  }
75
72
  };
76
73
  }
@@ -49,7 +49,7 @@ export default function {{COMPONENT_CLASS_NAME}}(props: {{COMPONENT_CLASS_NAME}}
49
49
  field.config.displayAsStatus = true;
50
50
  }
51
51
 
52
- return getPConnect().createComponent(field, '', '', {}); // 2nd, 3rd, and 4th args empty string/object/null until typedef marked correctly as optional
52
+ return getPConnect().createComponent(field, '', 0, {}); // 2nd, 3rd, and 4th args empty string/object/null until typedef marked correctly as optional
53
53
  });
54
54
  }
55
55
 
@@ -108,6 +108,9 @@ export const compileMustacheTemplates = async (
108
108
  case 'Picklist-RadioButtons':
109
109
  mustacheSubType = 'Picklist';
110
110
  break;
111
+ case 'Icon-Button-URL':
112
+ mustacheSubType = 'Text-URL';
113
+ break;
111
114
  }
112
115
  }
113
116
 
@@ -141,6 +141,7 @@ export const zipComponent = async (componentKey, category = CATEGORY_CUSTOM) =>
141
141
 
142
142
  const configJson = `${srcDirectory}/config.json`;
143
143
  const configExtJson = `${srcDirectory}/config-ext.json`;
144
+ const localizationJson = `${srcDirectory}/localizations.json`;
144
145
 
145
146
  const zip = new AdmZip();
146
147
 
@@ -148,6 +149,9 @@ export const zipComponent = async (componentKey, category = CATEGORY_CUSTOM) =>
148
149
  if (category === CATEGORY_CUSTOM || category == CATEGORY_CONSTELLATION) {
149
150
  zip.addLocalFolder(srcDirectory, 'src/');
150
151
  zip.addLocalFile(configJson);
152
+ if (fs.existsSync(localizationJson)) {
153
+ zip.addLocalFile(localizationJson);
154
+ }
151
155
  }
152
156
  else {
153
157
  // check to see if have file
@@ -127,6 +127,7 @@ export const zipComponent = async (componentKey, category = CATEGORY_CUSTOM) =>
127
127
  const buildDirectory = await path.join(path.resolve(), 'dist/components', componentKey);
128
128
  const configJson = `${srcDirectory}/config.json`;
129
129
  const configExtJson = `${srcDirectory}/config-ext.json`;
130
+ const localizationJson = `${srcDirectory}/localizations.json`;
130
131
 
131
132
  const zip = new AdmZip();
132
133
 
@@ -134,6 +135,9 @@ export const zipComponent = async (componentKey, category = CATEGORY_CUSTOM) =>
134
135
  if (category === CATEGORY_CUSTOM || category == CATEGORY_CONSTELLATION) {
135
136
  zip.addLocalFolder(srcDirectory, 'src/');
136
137
  zip.addLocalFile(configJson);
138
+ if (fs.existsSync(localizationJson)) {
139
+ zip.addLocalFile(localizationJson);
140
+ }
137
141
  }
138
142
  else {
139
143
  // check to see if have file
@@ -151,7 +155,7 @@ export const zipComponent = async (componentKey, category = CATEGORY_CUSTOM) =>
151
155
  let configContent = "{ }";
152
156
  if (category === CATEGORY_CUSTOM || category === CATEGORY_CONSTELLATION) {
153
157
  configContent = Buffer.from(fs.readFileSync(`${srcDirectory}/config.json`)).toString();
154
-
158
+
155
159
  // cleanup will remove this directory
156
160
 
157
161
  }
@@ -160,7 +164,7 @@ export const zipComponent = async (componentKey, category = CATEGORY_CUSTOM) =>
160
164
  configContent = Buffer.from(fs.readFileSync(`${srcDirectory}/config-ext.json`)).toString();
161
165
 
162
166
  // cleanup will remove this directory
163
-
167
+
164
168
  }
165
169
  else {
166
170
  const tempConfig = { "componentKey" : ""};
@@ -365,7 +365,13 @@ export default async (option, category = CATEGORY_CUSTOM) => {
365
365
  }
366
366
 
367
367
  // const data = JSON.parse(fs.readFileSync(path.resolve(configFile), 'utf8'));
368
- const data = JSON.parse(configData);
368
+ let data;
369
+ try {
370
+ data = JSON.parse(configData);
371
+ }
372
+ catch (er) {
373
+ throw new Error(`Invalid schema json in config.json: ${er}`);
374
+ }
369
375
 
370
376
  // for now a special case for ScalarList & Group, those doesn't have a "subtype", so for now manualy
371
377
  // add one in here, just to pass validation