@pega/custom-dx-components 0.0.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.
- package/.eslintrc.json +18 -0
- package/.prettierignore +2 -0
- package/.prettierrc.json +1 -0
- package/.vscode/extensions.json +9 -0
- package/.vscode/settings.json +48 -0
- package/LICENSE +185 -0
- package/README.md +204 -0
- package/bin/index.js +5 -0
- package/cspell.json +26 -0
- package/package.json +67 -0
- package/src/cli.js +92 -0
- package/src/constants.js +92 -0
- package/src/tasks/authenticate/helper.js +60 -0
- package/src/tasks/authenticate/index.js +75 -0
- package/src/tasks/create/index.js +304 -0
- package/src/tasks/create/template/config.json.mustache +67 -0
- package/src/tasks/create/template/demo.stories.jsx.mustache +44 -0
- package/src/tasks/create/template/index.jsx.mustache +55 -0
- package/src/tasks/create/template/styles.js.mustache +7 -0
- package/src/tasks/delete/helper.js +105 -0
- package/src/tasks/delete/index.js +45 -0
- package/src/tasks/index.js +9 -0
- package/src/tasks/init/helper.js +63 -0
- package/src/tasks/init/index.js +165 -0
- package/src/tasks/init/template/.eslintrc.json +10 -0
- package/src/tasks/init/template/.prettierrc.json +1 -0
- package/src/tasks/init/template/.storybook/main.js +6 -0
- package/src/tasks/init/template/.storybook/pega-logo.svg +16 -0
- package/src/tasks/init/template/.storybook/preview.tsx +44 -0
- package/src/tasks/init/template/.storybook/theme.js +44 -0
- package/src/tasks/init/template/.stylelintrc.json +4 -0
- package/src/tasks/init/template/.vscode/extensions.json +9 -0
- package/src/tasks/init/template/.vscode/settings.json +48 -0
- package/src/tasks/init/template/README.md +204 -0
- package/src/tasks/init/template/build.config.json +1 -0
- package/src/tasks/init/template/cspell.json +14 -0
- package/src/tasks/init/template/package.json.mustache +69 -0
- package/src/tasks/init/template/src/components/MBTAList/MBTAList.stories.tsx +10 -0
- package/src/tasks/init/template/src/components/MBTAList/MBTAList.tsx +122 -0
- package/src/tasks/init/template/src/components/MBTAList/icons/accessible.icon.tsx +14 -0
- package/src/tasks/init/template/src/components/MBTAList/icons/bus.icon.tsx +13 -0
- package/src/tasks/init/template/src/components/MBTAList/icons/mbta.icon.tsx +10 -0
- package/src/tasks/init/template/src/components/MBTAList/icons/subway.icon.tsx +14 -0
- package/src/tasks/init/template/src/components/MBTAList/index.ts +2 -0
- package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURL.stories.tsx +19 -0
- package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURL.styles.ts +5 -0
- package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURL.types.ts +10 -0
- package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURLDisplay.tsx +25 -0
- package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURLInput.tsx +24 -0
- package/src/tasks/init/template/src/components/Organization_Library_MediaURL/config.json +13 -0
- package/src/tasks/init/template/src/components/Organization_Library_MediaURL/index.ts +2 -0
- package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/config.json +44 -0
- package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/demo.stories.jsx +40 -0
- package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/index.jsx +42 -0
- package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/styles.js +5 -0
- package/src/tasks/init/template/tasks.config.json +21 -0
- package/src/tasks/init/template/tsconfig.build.json +16 -0
- package/src/tasks/init/template/tsconfig.json +8 -0
- package/src/tasks/list/helper.js +118 -0
- package/src/tasks/list/index.js +51 -0
- package/src/tasks/publish/bundle/builder/index.js +174 -0
- package/src/tasks/publish/bundle/builder/modules.js +139 -0
- package/src/tasks/publish/bundle/builder/paths.js +50 -0
- package/src/tasks/publish/bundle/builder/webpack.config.js +334 -0
- package/src/tasks/publish/bundle/index.js +65 -0
- package/src/tasks/publish/helper.js +145 -0
- package/src/tasks/publish/index.js +55 -0
- package/src/tasks/update/index.js +5 -0
- package/src/tasks/upgrade/index.js +31 -0
- package/src/tasks/validator/index.js +102 -0
- package/src/util.js +277 -0
package/src/constants.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// cSpell:ignore words timeofday caseview casepreview objectview
|
|
2
|
+
export const TASKS_CONFIG_JSON_FILENAME = 'tasks.config.json';
|
|
3
|
+
export const BUILD_CONFIG_JSON_FILENAME = 'build.config.json';
|
|
4
|
+
export const COMPONENTS_DIRECTORY_PATH = 'components-directory-path';
|
|
5
|
+
export const TOKEN_PATH = 'node_modules/@pega/custom-dx-components/.access_token';
|
|
6
|
+
export const OOTB_COMPONENTS = 'node_modules/@pega/custom-dx-components/.ootb_components';
|
|
7
|
+
|
|
8
|
+
/* REST end points */
|
|
9
|
+
export const PUBLISH_COMPONENT_SERVICE_REST_ENDPOINT = 'PRRestService/dev/v1/publish_component';
|
|
10
|
+
export const LIST_COMPONENT_SERVICE_REST_ENDPOINT = 'PRRestService/dev/v1/list_component';
|
|
11
|
+
export const OOTB_COMPONENT_SERVICE_REST_ENDPOINT = 'PRRestService/dev/v1/ootb_component';
|
|
12
|
+
export const DELETE_COMPONENT_SERVICE_REST_ENDPOINT = 'PRRestService/dev/v1/delete_component';
|
|
13
|
+
export const TOKEN_URL_V1 = 'PRRestService/oauth2/v1/token';
|
|
14
|
+
|
|
15
|
+
export const COMPONENT_SCHEMA = {
|
|
16
|
+
type: [
|
|
17
|
+
{
|
|
18
|
+
name: 'Field',
|
|
19
|
+
value: 'Field'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'Layout template',
|
|
23
|
+
value: 'Template'
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'Widget',
|
|
27
|
+
value: 'Widget'
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
subtype: {
|
|
31
|
+
field: [
|
|
32
|
+
{
|
|
33
|
+
name: 'Text',
|
|
34
|
+
value: 'Text'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'Paragraph',
|
|
38
|
+
value: 'Text-Paragraph'
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'Email',
|
|
42
|
+
value: 'Email'
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'Phone',
|
|
46
|
+
value: 'Phone'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'URL',
|
|
50
|
+
value: 'URL'
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'Integer',
|
|
54
|
+
value: 'Integer'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'Decimal',
|
|
58
|
+
value: 'Decimal'
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'Currency',
|
|
62
|
+
value: 'Decimal-Currency'
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'Percentage',
|
|
66
|
+
value: 'Decimal-Percentage'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'Boolean',
|
|
70
|
+
value: 'Boolean'
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'Date',
|
|
74
|
+
value: 'Date'
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'DateTime',
|
|
78
|
+
value: 'DateTime'
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'TimeofDay',
|
|
82
|
+
value: 'TimeofDay'
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'Picklist',
|
|
86
|
+
value: 'Picklist'
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
template: ['DETAILS', 'FORM', 'PAGE'],
|
|
90
|
+
widget: ['PAGE', 'CASE']
|
|
91
|
+
}
|
|
92
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export */
|
|
2
|
+
import { getPegaServerConfig } from '../../util.js';
|
|
3
|
+
|
|
4
|
+
export const getAuthQuestions = async () => {
|
|
5
|
+
const defaultPegaConfig = await getPegaServerConfig();
|
|
6
|
+
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
name: 'server',
|
|
10
|
+
message: 'Enter pega server url',
|
|
11
|
+
default: defaultPegaConfig.server
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: 'user',
|
|
15
|
+
message: 'Enter user id',
|
|
16
|
+
default: defaultPegaConfig.user,
|
|
17
|
+
validate: value => {
|
|
18
|
+
if (value.trim()) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
return 'Username cannot be empty';
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'password',
|
|
26
|
+
type: 'password',
|
|
27
|
+
message: 'Enter password',
|
|
28
|
+
default: defaultPegaConfig.password,
|
|
29
|
+
validate: value => {
|
|
30
|
+
if (value.trim()) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return 'Password cannot be empty';
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'clientId',
|
|
38
|
+
message: 'Enter clientId',
|
|
39
|
+
default: defaultPegaConfig.clientId,
|
|
40
|
+
validate: value => {
|
|
41
|
+
if (value.trim()) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
return 'clientId cannot be empty';
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'clientSecret',
|
|
49
|
+
type: 'password',
|
|
50
|
+
message: 'Enter clientSecret',
|
|
51
|
+
default: defaultPegaConfig.clientSecret,
|
|
52
|
+
validate: value => {
|
|
53
|
+
if (value.trim()) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return 'clientSecret cannot be empty';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
];
|
|
60
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import https from 'https';
|
|
4
|
+
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import inquirer from 'inquirer';
|
|
7
|
+
import fetch from 'node-fetch';
|
|
8
|
+
|
|
9
|
+
import { checkPathAccess, getTokenUrl } from '../../util.js';
|
|
10
|
+
import { TOKEN_PATH } from '../../constants.js';
|
|
11
|
+
|
|
12
|
+
import { getAuthQuestions } from './helper.js';
|
|
13
|
+
|
|
14
|
+
export const TASKS_CONFIG_JSON_FILENAME = 'tasks.config.json';
|
|
15
|
+
|
|
16
|
+
const pegaConfigJsonPath = path.join(path.resolve(), TASKS_CONFIG_JSON_FILENAME);
|
|
17
|
+
|
|
18
|
+
const generateAccessToken = async config => {
|
|
19
|
+
const formData = new URLSearchParams();
|
|
20
|
+
formData.append('client_id', config.clientId);
|
|
21
|
+
formData.append('client_secret', config.clientSecret);
|
|
22
|
+
formData.append('username', config.user);
|
|
23
|
+
formData.append('password', config.password);
|
|
24
|
+
formData.append('grant_type', 'password');
|
|
25
|
+
|
|
26
|
+
const accessTokenUri = await getTokenUrl(config.server);
|
|
27
|
+
fetch(accessTokenUri, {
|
|
28
|
+
agent: new https.Agent({ rejectUnauthorized: false }),
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
31
|
+
body: formData.toString()
|
|
32
|
+
})
|
|
33
|
+
.then(response => response.json())
|
|
34
|
+
.then(data => {
|
|
35
|
+
if (data && data.errors) {
|
|
36
|
+
const errMessages = data.errors;
|
|
37
|
+
errMessages.forEach(msgArr => {
|
|
38
|
+
throw new Error(`Failed with error - ${JSON.stringify(msgArr.message)}`);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (data.token_type) {
|
|
42
|
+
fs.writeFile(TOKEN_PATH, JSON.stringify(data), err => {
|
|
43
|
+
if (err) {
|
|
44
|
+
console.error(err);
|
|
45
|
+
}
|
|
46
|
+
console.log(`${chalk.bold.green('Authenticated successfully !!')}`);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
.catch(e => console.log(`${chalk.bold.red(e)}`));
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default async options => {
|
|
54
|
+
await checkPathAccess(pegaConfigJsonPath);
|
|
55
|
+
|
|
56
|
+
let data = fs.readFileSync(pegaConfigJsonPath, { encoding: 'utf8' });
|
|
57
|
+
data = data && JSON.parse(data);
|
|
58
|
+
|
|
59
|
+
const serverConfig = data['server-config'];
|
|
60
|
+
const params = options.params;
|
|
61
|
+
|
|
62
|
+
const questions = await getAuthQuestions(params);
|
|
63
|
+
const answers = await inquirer.prompt(questions);
|
|
64
|
+
serverConfig.server = answers.server;
|
|
65
|
+
serverConfig.user = answers.user;
|
|
66
|
+
serverConfig.password = answers.password;
|
|
67
|
+
serverConfig.clientId = answers.clientId;
|
|
68
|
+
serverConfig.clientSecret = answers.clientSecret;
|
|
69
|
+
await generateAccessToken(serverConfig);
|
|
70
|
+
|
|
71
|
+
data = JSON.stringify(data, null, 2);
|
|
72
|
+
fs.writeFile(pegaConfigJsonPath, data, err => {
|
|
73
|
+
if (err) throw err;
|
|
74
|
+
});
|
|
75
|
+
};
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { URL, fileURLToPath } from 'url';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import { promisify } from 'util';
|
|
5
|
+
|
|
6
|
+
import inquirer from 'inquirer';
|
|
7
|
+
import ncp from 'ncp';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
convertIntoPascalCase,
|
|
12
|
+
compileMustacheTemplate,
|
|
13
|
+
getComponentDirectoryPath,
|
|
14
|
+
getComponents,
|
|
15
|
+
getComponentDefaults,
|
|
16
|
+
sanitize,
|
|
17
|
+
validateSemver
|
|
18
|
+
} from '../../util.js';
|
|
19
|
+
import { COMPONENT_SCHEMA } from '../../constants.js';
|
|
20
|
+
|
|
21
|
+
const copy = promisify(ncp);
|
|
22
|
+
|
|
23
|
+
const copyComponentTemplate = async options => {
|
|
24
|
+
return copy(options.templateDirectory, options.targetDirectory, {
|
|
25
|
+
clobber: false
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const compileMustacheTemplates = async (
|
|
30
|
+
componentDirectory,
|
|
31
|
+
{
|
|
32
|
+
componentKey,
|
|
33
|
+
componentName,
|
|
34
|
+
componentLabel,
|
|
35
|
+
library,
|
|
36
|
+
version,
|
|
37
|
+
type,
|
|
38
|
+
subtype,
|
|
39
|
+
description,
|
|
40
|
+
organization,
|
|
41
|
+
allowedApplications
|
|
42
|
+
}
|
|
43
|
+
) => {
|
|
44
|
+
const files = fs.readdirSync(componentDirectory);
|
|
45
|
+
const componentClassName = convertIntoPascalCase(componentKey);
|
|
46
|
+
|
|
47
|
+
const isTemplate = type === 'Template';
|
|
48
|
+
const isPicklist = subtype === 'Picklist';
|
|
49
|
+
const isBool = subtype === 'Boolean';
|
|
50
|
+
const isPhone = subtype === 'Phone';
|
|
51
|
+
|
|
52
|
+
if (Array.isArray(subtype) && subtype.length === 1) {
|
|
53
|
+
subtype = subtype.toString();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (allowedApplications.trim() === '') {
|
|
57
|
+
allowedApplications = [];
|
|
58
|
+
} else {
|
|
59
|
+
if (allowedApplications.indexOf(',') !== -1) {
|
|
60
|
+
allowedApplications = allowedApplications.split(',');
|
|
61
|
+
}
|
|
62
|
+
allowedApplications = [].concat(allowedApplications);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
allowedApplications = allowedApplications.filter(el => !!el.trim()).map(el => el.trim());
|
|
66
|
+
files.forEach(file => {
|
|
67
|
+
const filePath = path.join(componentDirectory, file);
|
|
68
|
+
|
|
69
|
+
const output = compileMustacheTemplate(filePath, {
|
|
70
|
+
COMPONENT_KEY: componentKey,
|
|
71
|
+
COMPONENT_NAME: componentName,
|
|
72
|
+
COMPONENT_LABEL: componentLabel,
|
|
73
|
+
COMPONENT_CLASS_NAME: componentClassName,
|
|
74
|
+
ORGANIZATION: organization,
|
|
75
|
+
VERSION: version,
|
|
76
|
+
LIBRARY: library,
|
|
77
|
+
ALLOWEDAPPS: JSON.stringify(allowedApplications),
|
|
78
|
+
TYPE: type,
|
|
79
|
+
SUB_TYPE: JSON.stringify(subtype),
|
|
80
|
+
DESCRIPTION: description,
|
|
81
|
+
IS_TEMPLATE: isTemplate,
|
|
82
|
+
IS_PICKLIST: isPicklist,
|
|
83
|
+
IS_BOOLEAN: isBool,
|
|
84
|
+
IS_PHONE: isPhone
|
|
85
|
+
});
|
|
86
|
+
fs.writeFileSync(filePath, output);
|
|
87
|
+
fs.renameSync(filePath, filePath.replace('.mustache', ''));
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const validateCompile = async (
|
|
92
|
+
{
|
|
93
|
+
componentName,
|
|
94
|
+
componentLabel,
|
|
95
|
+
library,
|
|
96
|
+
version,
|
|
97
|
+
type,
|
|
98
|
+
subtype,
|
|
99
|
+
description,
|
|
100
|
+
allowedApplications
|
|
101
|
+
},
|
|
102
|
+
options
|
|
103
|
+
) => {
|
|
104
|
+
const templateDirectory = fileURLToPath(new URL('./template', import.meta.url));
|
|
105
|
+
|
|
106
|
+
const { organization } = JSON.parse(fs.readFileSync(path.resolve('package.json'), 'utf8'));
|
|
107
|
+
|
|
108
|
+
const componentKey = `${organization}_${library}_${componentName}`;
|
|
109
|
+
/*
|
|
110
|
+
if (!isPascalCase(componentKey)) {
|
|
111
|
+
console.log(
|
|
112
|
+
chalk.yellowBright(
|
|
113
|
+
`${componentKey} is not in Pascal Case. Attempting to create component in Pascal Case !!`
|
|
114
|
+
)
|
|
115
|
+
);
|
|
116
|
+
componentKey = convertIntoPascalCase(componentKey);
|
|
117
|
+
} */
|
|
118
|
+
|
|
119
|
+
const targetDirectory = await getComponentDirectoryPath(componentKey);
|
|
120
|
+
|
|
121
|
+
const components = await getComponents();
|
|
122
|
+
if (components.includes(componentKey)) {
|
|
123
|
+
console.log(chalk.red(`${componentKey} component already exists in ${targetDirectory}`));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
await copyComponentTemplate({
|
|
128
|
+
...options,
|
|
129
|
+
targetDirectory,
|
|
130
|
+
templateDirectory
|
|
131
|
+
});
|
|
132
|
+
await compileMustacheTemplates(targetDirectory, {
|
|
133
|
+
componentKey,
|
|
134
|
+
componentName,
|
|
135
|
+
componentLabel,
|
|
136
|
+
library,
|
|
137
|
+
version,
|
|
138
|
+
type,
|
|
139
|
+
subtype,
|
|
140
|
+
description,
|
|
141
|
+
organization,
|
|
142
|
+
allowedApplications
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
console.log(chalk.green(`${componentKey} component is created in ${targetDirectory}`));
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export default async options => {
|
|
149
|
+
if (options.params[9]) {
|
|
150
|
+
const componentName = options.params[3];
|
|
151
|
+
const componentLabel = options.params[4];
|
|
152
|
+
const library = options.params[5];
|
|
153
|
+
const version = options.params[6];
|
|
154
|
+
const type = options.params[7];
|
|
155
|
+
const subtype = options.params[8];
|
|
156
|
+
const description = options.params[9];
|
|
157
|
+
await validateCompile(
|
|
158
|
+
{
|
|
159
|
+
componentName,
|
|
160
|
+
componentLabel,
|
|
161
|
+
library,
|
|
162
|
+
version,
|
|
163
|
+
type,
|
|
164
|
+
subtype,
|
|
165
|
+
description
|
|
166
|
+
},
|
|
167
|
+
options
|
|
168
|
+
);
|
|
169
|
+
} else {
|
|
170
|
+
const componentDefaults = await getComponentDefaults();
|
|
171
|
+
const questions = [
|
|
172
|
+
{
|
|
173
|
+
name: 'componentName',
|
|
174
|
+
message: 'Enter component name (required)',
|
|
175
|
+
validate: value => {
|
|
176
|
+
/* value should not be empty
|
|
177
|
+
It should not have spaces
|
|
178
|
+
It should not start with a number
|
|
179
|
+
Only case-insensitive alphanumeric values are allowed
|
|
180
|
+
*/
|
|
181
|
+
if (value && !/^\d/.test(value) && value === sanitize(value)) {
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
return 'Only alphanumeric values are allowed, starting with alphabets';
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: 'componentLabel',
|
|
189
|
+
message: 'Enter component label for display (required)',
|
|
190
|
+
validate: value => {
|
|
191
|
+
if (value) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
return 'Please provide value for label';
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: 'version',
|
|
199
|
+
message: 'Enter component version',
|
|
200
|
+
validate: value => {
|
|
201
|
+
if (validateSemver(value)) {
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
return 'Please provide semver compatible version e.g 0.0.1';
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: 'library',
|
|
209
|
+
message: 'Enter library name (required)',
|
|
210
|
+
default: componentDefaults.library,
|
|
211
|
+
validate: value => {
|
|
212
|
+
/* value should not be empty
|
|
213
|
+
It should not have spaces
|
|
214
|
+
It should not start with a number
|
|
215
|
+
Only case-insensitive alphanumeric values are allowed
|
|
216
|
+
*/
|
|
217
|
+
if (value && !/^\d/.test(value) && value === sanitize(value)) {
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
return 'Only alphanumeric values are allowed, starting with alphabets';
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: 'allowedApplications',
|
|
225
|
+
message: 'Please enter the application names to be supported (comma-separated). ',
|
|
226
|
+
suffix: 'Keep empty for all applications'
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: 'type',
|
|
230
|
+
type: 'rawlist',
|
|
231
|
+
message: 'Enter type of component',
|
|
232
|
+
default: componentDefaults.type,
|
|
233
|
+
choices: COMPONENT_SCHEMA.type
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: 'subtype',
|
|
237
|
+
type: 'rawlist',
|
|
238
|
+
message: 'Enter subtype of component',
|
|
239
|
+
default: componentDefaults.subtype,
|
|
240
|
+
choices: COMPONENT_SCHEMA.subtype.field,
|
|
241
|
+
when(answers) {
|
|
242
|
+
return answers.type === 'Field';
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: 'subtype',
|
|
247
|
+
type: 'rawlist',
|
|
248
|
+
message: 'Enter subtype of component',
|
|
249
|
+
default: componentDefaults.subtype,
|
|
250
|
+
choices: COMPONENT_SCHEMA.subtype.template,
|
|
251
|
+
when(answers) {
|
|
252
|
+
return answers.type === 'Template';
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
name: 'subtype',
|
|
257
|
+
type: 'checkbox',
|
|
258
|
+
message: 'Enter subtype of component',
|
|
259
|
+
default: [componentDefaults.subtype || COMPONENT_SCHEMA.subtype.widget[0]],
|
|
260
|
+
choices: COMPONENT_SCHEMA.subtype.widget,
|
|
261
|
+
when(answers) {
|
|
262
|
+
return answers.type === 'Widget';
|
|
263
|
+
},
|
|
264
|
+
validate: value => {
|
|
265
|
+
/* value should not be empty */
|
|
266
|
+
if (Array.isArray(value) && value.length) {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
return 'Please select subtype';
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
name: 'description',
|
|
274
|
+
message: 'Enter description for the component',
|
|
275
|
+
default: componentDefaults.description
|
|
276
|
+
}
|
|
277
|
+
];
|
|
278
|
+
await inquirer.prompt(questions).then(async answers => {
|
|
279
|
+
const {
|
|
280
|
+
componentName,
|
|
281
|
+
componentLabel,
|
|
282
|
+
library,
|
|
283
|
+
version,
|
|
284
|
+
type,
|
|
285
|
+
subtype,
|
|
286
|
+
description,
|
|
287
|
+
allowedApplications
|
|
288
|
+
} = answers;
|
|
289
|
+
await validateCompile(
|
|
290
|
+
{
|
|
291
|
+
componentName,
|
|
292
|
+
componentLabel,
|
|
293
|
+
library,
|
|
294
|
+
version,
|
|
295
|
+
type,
|
|
296
|
+
subtype,
|
|
297
|
+
description,
|
|
298
|
+
allowedApplications
|
|
299
|
+
},
|
|
300
|
+
options
|
|
301
|
+
);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
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
|
+
{{#IS_TEMPLATE}}
|
|
13
|
+
"icon": "images/pz-text-input-active.svg",
|
|
14
|
+
{{/IS_TEMPLATE}}
|
|
15
|
+
"properties": [
|
|
16
|
+
{
|
|
17
|
+
"name": "value",
|
|
18
|
+
"label": "Property",
|
|
19
|
+
"format": "PROPERTY"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "label",
|
|
23
|
+
"label": "Label value",
|
|
24
|
+
"format": "TEXT"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "placeholder",
|
|
28
|
+
"label": "Placeholder",
|
|
29
|
+
"format": "TEXT"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "visibility",
|
|
33
|
+
"label": "Visible",
|
|
34
|
+
"format": "VISIBILITY"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "disabled",
|
|
38
|
+
"label": "Disabled",
|
|
39
|
+
"format": "DISABLED"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "required",
|
|
43
|
+
"label": "Required",
|
|
44
|
+
"format": "REQUIRED"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"defaultConfig": {
|
|
48
|
+
{{#IS_PICKLIST}}
|
|
49
|
+
"label": "@L $this.label",
|
|
50
|
+
"placeholder": "@L Select...",
|
|
51
|
+
"listType": "associated",
|
|
52
|
+
"datasource": "@ASSOCIATED .$this.name"
|
|
53
|
+
{{/IS_PICKLIST}}
|
|
54
|
+
{{#IS_BOOLEAN}}
|
|
55
|
+
"trueText": "True",
|
|
56
|
+
"falseText": "False"
|
|
57
|
+
{{/IS_BOOLEAN}}
|
|
58
|
+
{{#IS_PHONE}}
|
|
59
|
+
"datasource": {
|
|
60
|
+
"source": "@DATASOURCE D_pyCountryCallingCodeList.pxResults",
|
|
61
|
+
"fields": {
|
|
62
|
+
"value": "@P .pyCallingCode"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
{{/IS_PHONE}}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { withKnobs, text, boolean } from '@storybook/addon-knobs';
|
|
3
|
+
|
|
4
|
+
import {{COMPONENT_CLASS_NAME}} from './index.jsx';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: '{{COMPONENT_CLASS_NAME}}',
|
|
8
|
+
decorators: [withKnobs],
|
|
9
|
+
component: {{COMPONENT_CLASS_NAME}}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const base{{COMPONENT_CLASS_NAME}} = () => {
|
|
13
|
+
const [value, setValue] = useState('test value');
|
|
14
|
+
|
|
15
|
+
const props = {
|
|
16
|
+
getPConnect: () => {
|
|
17
|
+
return {
|
|
18
|
+
getActionsApi: () => {
|
|
19
|
+
return {
|
|
20
|
+
updateFieldValue: (propName, value) => {
|
|
21
|
+
setValue(value);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
getStateProps: () => {
|
|
26
|
+
return { value: '.name' };
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
value,
|
|
31
|
+
placeholder: text('Placeholder', 'Test placeholder'),
|
|
32
|
+
disabled: boolean('Disabled', false),
|
|
33
|
+
readOnly: boolean('Disabled', false),
|
|
34
|
+
required: boolean('Disabled', false),
|
|
35
|
+
label: text('Label', 'Sample Label'),
|
|
36
|
+
testId: text('Test id', 'text-12344566')
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<>
|
|
41
|
+
<{{COMPONENT_CLASS_NAME}} {...props} />
|
|
42
|
+
</>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import PropTypes from 'prop-types';
|
|
2
|
+
import { Input, Label } from '@pega/cosmos-react-core';
|
|
3
|
+
|
|
4
|
+
import Styled{{COMPONENT_CLASS_NAME}}Wrapper from './styles';
|
|
5
|
+
|
|
6
|
+
const {{COMPONENT_CLASS_NAME}} = props => {
|
|
7
|
+
const { getPConnect, value, placeholder, disabled, readOnly, required, label, testId } = props;
|
|
8
|
+
|
|
9
|
+
const pConn = getPConnect();
|
|
10
|
+
const actions = pConn.getActionsApi();
|
|
11
|
+
const propName = pConn?.getStateProps()?.value;
|
|
12
|
+
|
|
13
|
+
const handleOnChange = event => {
|
|
14
|
+
const { value: updatedValue } = event.target;
|
|
15
|
+
actions.updateFieldValue(propName, updatedValue);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Styled{{COMPONENT_CLASS_NAME}}Wrapper>
|
|
20
|
+
<Label>{label}</Label>
|
|
21
|
+
<Input
|
|
22
|
+
type='text'
|
|
23
|
+
value={value}
|
|
24
|
+
placeholder={placeholder}
|
|
25
|
+
disabled={disabled}
|
|
26
|
+
readOnly={readOnly}
|
|
27
|
+
required={required}
|
|
28
|
+
onChange={handleOnChange}
|
|
29
|
+
testId={testId}
|
|
30
|
+
/>
|
|
31
|
+
</Styled{{COMPONENT_CLASS_NAME}}Wrapper>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
{{COMPONENT_CLASS_NAME}}.defaultProps = {
|
|
36
|
+
value: '',
|
|
37
|
+
placeholder: '',
|
|
38
|
+
disabled: false,
|
|
39
|
+
readOnly: false,
|
|
40
|
+
required: false,
|
|
41
|
+
testId: null
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
{{COMPONENT_CLASS_NAME}}.propTypes = {
|
|
45
|
+
label: PropTypes.string,
|
|
46
|
+
value: PropTypes.string,
|
|
47
|
+
placeholder: PropTypes.string,
|
|
48
|
+
getPConnect: PropTypes.func.isRequired,
|
|
49
|
+
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
|
|
50
|
+
readOnly: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
|
|
51
|
+
required: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
|
|
52
|
+
testId: PropTypes.string
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default {{COMPONENT_CLASS_NAME}};
|