@pega/dx-component-builder-sdk 0.1.24 → 0.1.25
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 +2 -1
- package/src/auth.js +573 -0
- package/src/cli.js +1 -1
- package/src/constants.js +32 -1
- package/src/tasks/authenticate/helper.js +91 -8
- package/src/tasks/authenticate/index.js +137 -61
- package/src/tasks/create/index.js +6 -1
- package/src/tasks/create/templates/SDK-React/template/FORM-region/demo.stories.jsx.mustache +183 -0
- package/src/tasks/create/templates/SDK-React/template/FORM-region/mock.stories.js.mustache +132 -0
- package/src/tasks/publish/helper.js +6 -0
- package/src/tasks/publish/index.js +8 -1
- package/src/tasks/publish-all/helper.js +7 -0
- package/src/tasks/publish-all/index.js +8 -1
- package/src/util.js +0 -5
|
@@ -1,24 +1,98 @@
|
|
|
1
1
|
/* eslint-disable import/prefer-default-export */
|
|
2
2
|
import { getPegaServerConfig } from '../../util.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { AUTHENTICATE_SCHEMA } from '../../constants.js';
|
|
5
|
+
|
|
6
|
+
export const getAuthQuestions = async (dxcbConfig) => {
|
|
7
|
+
const defaultPegaConfig = dxcbConfig;
|
|
8
|
+
const aMustAsk = dxcbConfig['questions_askAlways'] ? dxcbConfig['questions_askAlways'].split(',') : [];
|
|
9
|
+
const aNeverAsk = dxcbConfig['questions_askNever'] ? dxcbConfig['questions_askNever'].split(',') : [];
|
|
10
|
+
|
|
11
|
+
const initAnswers = (answers) => {
|
|
12
|
+
// Setup default answers
|
|
13
|
+
answers.serverType = defaultPegaConfig.serverType || "infinity";
|
|
14
|
+
answers.server = defaultPegaConfig.server || undefined;
|
|
15
|
+
answers.isolationId = defaultPegaConfig.isolationId || undefined;
|
|
16
|
+
answers.clientId = defaultPegaConfig.clientId || undefined;
|
|
17
|
+
answers.grantType = defaultPegaConfig.grantType || "authCode";
|
|
18
|
+
answers.clientSecret = defaultPegaConfig.clientSecret || undefined;
|
|
19
|
+
answers.user = defaultPegaConfig.user || undefined;
|
|
20
|
+
answers.password = defaultPegaConfig.password || undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const fnStandardWhen = (prop, answers) => {
|
|
24
|
+
if (aNeverAsk.includes(prop)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return aMustAsk.includes(prop) || !answers[prop];
|
|
28
|
+
};
|
|
6
29
|
|
|
7
30
|
return [
|
|
31
|
+
{
|
|
32
|
+
name: 'serverType',
|
|
33
|
+
type: 'rawlist',
|
|
34
|
+
message: 'Enter Pega server type',
|
|
35
|
+
default: answers => {
|
|
36
|
+
return defaultPegaConfig.serverType;
|
|
37
|
+
},
|
|
38
|
+
choices: AUTHENTICATE_SCHEMA.serverType,
|
|
39
|
+
validate: value => {
|
|
40
|
+
if (value.trim()) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return 'Pega server type cannot be empty';
|
|
44
|
+
},
|
|
45
|
+
when: answers => {
|
|
46
|
+
initAnswers(answers);
|
|
47
|
+
return fnStandardWhen('serverType', answers);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
8
50
|
{
|
|
9
51
|
name: 'server',
|
|
10
52
|
message: 'Enter pega server url',
|
|
11
|
-
default: defaultPegaConfig.server
|
|
53
|
+
default: defaultPegaConfig.server,
|
|
54
|
+
when: answers =>{
|
|
55
|
+
return fnStandardWhen('server', answers);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'isolationId',
|
|
60
|
+
message: 'Enter isolation id',
|
|
61
|
+
default: defaultPegaConfig.isolationId,
|
|
62
|
+
when: answers => {
|
|
63
|
+
return answers.serverType === "launchpad" && fnStandardWhen('isolationId', answers);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'grantType',
|
|
68
|
+
type: 'rawlist',
|
|
69
|
+
message: 'Enter OAuth 2.0 grant type',
|
|
70
|
+
default: defaultPegaConfig.grantType,
|
|
71
|
+
choices: answers => {
|
|
72
|
+
return AUTHENTICATE_SCHEMA.grantType.filter(gt => !(answers.serverType === "launchpad" && gt.value === "passwordCreds"));
|
|
73
|
+
},
|
|
74
|
+
validate: value => {
|
|
75
|
+
if (value.trim()) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return 'Grant type cannot be empty';
|
|
79
|
+
},
|
|
80
|
+
when: answers => {
|
|
81
|
+
return fnStandardWhen('grantType', answers);
|
|
82
|
+
}
|
|
12
83
|
},
|
|
13
84
|
{
|
|
14
85
|
name: 'user',
|
|
15
86
|
message: 'Enter user id',
|
|
16
87
|
default: defaultPegaConfig.user,
|
|
17
|
-
validate: value => {
|
|
18
|
-
if (value.trim()) {
|
|
88
|
+
validate: (value, answers) => {
|
|
89
|
+
if (value.trim() || answers.grantType === "authCode") {
|
|
19
90
|
return true;
|
|
20
91
|
}
|
|
21
92
|
return 'Username cannot be empty';
|
|
93
|
+
},
|
|
94
|
+
when: answers => {
|
|
95
|
+
return (answers.serverType === "infinity" && answers.grantType === "passwordCreds") && fnStandardWhen('user', answers);
|
|
22
96
|
}
|
|
23
97
|
},
|
|
24
98
|
{
|
|
@@ -26,11 +100,14 @@ export const getAuthQuestions = async () => {
|
|
|
26
100
|
type: 'password',
|
|
27
101
|
message: 'Enter password',
|
|
28
102
|
default: defaultPegaConfig.password,
|
|
29
|
-
validate: value => {
|
|
30
|
-
if (value.trim()) {
|
|
103
|
+
validate: (value, answers) => {
|
|
104
|
+
if (value.trim() || answers.grantType === "authCode") {
|
|
31
105
|
return true;
|
|
32
106
|
}
|
|
33
107
|
return 'Password cannot be empty';
|
|
108
|
+
},
|
|
109
|
+
when: answers => {
|
|
110
|
+
return (answers.user && (answers.serverType === "infinity" && answers.grantType === "passwordCreds") && fnStandardWhen('password', answers));
|
|
34
111
|
}
|
|
35
112
|
},
|
|
36
113
|
{
|
|
@@ -42,6 +119,9 @@ export const getAuthQuestions = async () => {
|
|
|
42
119
|
return true;
|
|
43
120
|
}
|
|
44
121
|
return 'clientId cannot be empty';
|
|
122
|
+
},
|
|
123
|
+
when: answers => {
|
|
124
|
+
return fnStandardWhen('clientId', answers);
|
|
45
125
|
}
|
|
46
126
|
},
|
|
47
127
|
{
|
|
@@ -49,11 +129,14 @@ export const getAuthQuestions = async () => {
|
|
|
49
129
|
type: 'password',
|
|
50
130
|
message: 'Enter clientSecret',
|
|
51
131
|
default: defaultPegaConfig.clientSecret,
|
|
52
|
-
validate: value => {
|
|
132
|
+
validate: (value, answers) => {
|
|
53
133
|
if (value.trim()) {
|
|
54
134
|
return true;
|
|
55
135
|
}
|
|
56
136
|
return 'clientSecret cannot be empty';
|
|
137
|
+
},
|
|
138
|
+
when: answers => {
|
|
139
|
+
return (answers.grantType !== "authCode" && fnStandardWhen('clientSecret', answers));
|
|
57
140
|
}
|
|
58
141
|
}
|
|
59
142
|
];
|
|
@@ -1,90 +1,166 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import https from 'https';
|
|
2
|
+
import fs from 'node:fs';
|
|
4
3
|
|
|
5
4
|
import chalk from 'chalk';
|
|
6
5
|
import inquirer from 'inquirer';
|
|
7
|
-
import fetch from 'node-fetch';
|
|
8
6
|
|
|
9
|
-
import { checkPathAccess,
|
|
10
|
-
import { TOKEN_PATH,
|
|
7
|
+
import { checkPathAccess, showVersion } from '../../util.js';
|
|
8
|
+
import { TOKEN_PATH, TOKEN_URL_V1, AUTHORIZE_URL_V1, LP_TOKEN_URL, LP_AUTHORIZE_URL, SDK_CONFIG_JSON_FILENAME,
|
|
9
|
+
SERVER_CONFIG, DXCB_CONFIG, DXCB_PUBLISH_ACCESS, SERVER_TYPE, SERVER_REST_URL, LP_SERVER_REST_URL } from '../../constants.js';
|
|
11
10
|
|
|
12
11
|
import { getAuthQuestions } from './helper.js';
|
|
13
|
-
|
|
12
|
+
import PegaAuth from '../../auth.js';
|
|
14
13
|
|
|
15
14
|
const pegaConfigJsonPath = path.join(path.resolve(), SDK_CONFIG_JSON_FILENAME);
|
|
15
|
+
let server = null;
|
|
16
16
|
|
|
17
17
|
const generateAccessToken = async config => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
18
|
+
|
|
19
|
+
let authSuccess = false;
|
|
20
|
+
const { serverType, isolationId, grantType, clientId, clientSecret, user, password } = config;
|
|
21
|
+
// Try to gracefully deal with missing trailing slashes for server (and later conditionally for redirectUri)
|
|
22
|
+
const server = config.server.endsWith('/') ? config.server : `${config.server}/`;
|
|
23
|
+
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
const sTokenUri = `${server}${serverType === 'infinity' ? TOKEN_URL_V1 : LP_TOKEN_URL}`;
|
|
26
|
+
const sAuthorizeUri = `${server}${serverType === 'infinity' ? AUTHORIZE_URL_V1 : LP_AUTHORIZE_URL}`;
|
|
27
|
+
// console.log(`grantType: ${config.grantType}`);
|
|
28
|
+
|
|
29
|
+
const authCodeConfig = grantType === 'authCode' ? {
|
|
30
|
+
authorizeUri: sAuthorizeUri,
|
|
31
|
+
redirectUri: config.redirectUri.endsWith('/') ? config.redirectUri : `${config.redirectUri}/`,
|
|
32
|
+
cert: config.cert,
|
|
33
|
+
key: config.key,
|
|
34
|
+
winTitle: 'DX Component Dev',
|
|
35
|
+
winBodyHtml: `Authentication is complete. This browser window may be closed.`
|
|
36
|
+
} : {};
|
|
37
|
+
|
|
38
|
+
// Build auth config structure
|
|
39
|
+
const authConfig = {
|
|
40
|
+
serverType: serverType,
|
|
41
|
+
grantType: grantType,
|
|
42
|
+
tokenUri: sTokenUri,
|
|
43
|
+
clientId: clientId,
|
|
44
|
+
clientSecret: clientSecret,
|
|
45
|
+
ignoreInvalidCerts: true,
|
|
46
|
+
...authCodeConfig
|
|
47
|
+
};
|
|
48
|
+
if (serverType === 'infinity') {
|
|
49
|
+
authConfig.authService = 'pega';
|
|
50
|
+
if (grantType !== 'clientCreds' && user && password) {
|
|
51
|
+
authConfig.userIdentifier = user;
|
|
52
|
+
authConfig.password = Buffer.from(password).toString('base64');
|
|
53
53
|
}
|
|
54
|
-
}
|
|
55
|
-
|
|
54
|
+
}
|
|
55
|
+
if (serverType === 'launchpad') {
|
|
56
|
+
authConfig.isolationId = isolationId;
|
|
57
|
+
// authConfig.noPKCE = true;
|
|
58
|
+
}
|
|
59
|
+
const auth = new PegaAuth(authConfig);
|
|
60
|
+
// console.log(`...about to invoke auth.login\n${JSON.stringify(authConfig)}`);
|
|
61
|
+
|
|
62
|
+
auth.login()
|
|
63
|
+
.then((token) => {
|
|
64
|
+
if (token?.token_type) {
|
|
65
|
+
fs.writeFile(TOKEN_PATH, JSON.stringify(token), err => {
|
|
66
|
+
if (err) {
|
|
67
|
+
console.error(err);
|
|
68
|
+
return reject(authSuccess);
|
|
69
|
+
}
|
|
70
|
+
console.log(`${chalk.bold.green('Authenticated successfully !!')}`);
|
|
71
|
+
authSuccess = true;
|
|
72
|
+
return resolve(authSuccess);
|
|
73
|
+
});
|
|
74
|
+
} else {
|
|
75
|
+
console.log(`${chalk.bold.red('Authentication failed:' + JSON.stringify(token.errors ? token.errors : token))}`);
|
|
76
|
+
return reject(authSuccess);
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
.catch((e) => {
|
|
80
|
+
console.log(`${chalk.bold.red(e)}`);
|
|
81
|
+
return reject(authSuccess);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
56
84
|
};
|
|
57
85
|
|
|
58
86
|
export default async options => {
|
|
87
|
+
|
|
88
|
+
let authOK = false;
|
|
89
|
+
|
|
59
90
|
showVersion();
|
|
60
91
|
|
|
61
92
|
await checkPathAccess(pegaConfigJsonPath);
|
|
62
93
|
|
|
63
|
-
let
|
|
64
|
-
data =
|
|
94
|
+
let cfgData = fs.readFileSync(pegaConfigJsonPath, { encoding: 'utf8' });
|
|
95
|
+
let data = null;
|
|
96
|
+
if (cfgData) {
|
|
97
|
+
try {
|
|
98
|
+
data = JSON.parse(cfgData);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
const msg = `Invalid JSON within ${SDK_CONFIG_JSON_FILENAME}`;
|
|
101
|
+
console.log(`${chalk.red(msg)}`);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
65
105
|
|
|
66
106
|
if (!data[SERVER_CONFIG] || !data[SERVER_CONFIG][SERVER_REST_URL]) {
|
|
67
107
|
console.error(
|
|
68
|
-
`${chalk.red.bold('ERROR')}
|
|
108
|
+
`${chalk.red.bold('ERROR')} ${SERVER_CONFIG}.${SERVER_REST_URL} property not found within ${SDK_CONFIG_JSON_FILENAME}`
|
|
69
109
|
);
|
|
70
110
|
process.exit(1);
|
|
71
111
|
}
|
|
72
112
|
|
|
73
|
-
|
|
74
|
-
const serverConfig =
|
|
75
|
-
|
|
113
|
+
// Note: serverConfig below is actually dxcbConfig.
|
|
114
|
+
const serverConfig = data[DXCB_CONFIG][DXCB_PUBLISH_ACCESS];
|
|
115
|
+
serverConfig.serverType = data[SERVER_CONFIG][SERVER_TYPE] || "infinity";
|
|
116
|
+
serverConfig.server = data[SERVER_CONFIG][serverConfig.serverType === "infinity" ? SERVER_REST_URL : LP_SERVER_REST_URL];
|
|
117
|
+
const isPwdNonEmpty = serverConfig['password'] ? true : false;
|
|
76
118
|
|
|
77
|
-
const questions = await getAuthQuestions(
|
|
119
|
+
const questions = await getAuthQuestions(serverConfig);
|
|
78
120
|
const answers = await inquirer.prompt(questions);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
121
|
+
const aProps = ['serverType','server','isolationId','clientId','grantType','clientSecret','user','password'];
|
|
122
|
+
const isLaunchPad = answers.serverType === "launchpad";
|
|
123
|
+
let bWriteUpdate = false;
|
|
124
|
+
for (let i = 0; i < aProps.length; i += 1) {
|
|
125
|
+
const prop = aProps[i];
|
|
126
|
+
if (serverConfig[prop] !== answers[prop]) {
|
|
127
|
+
// console.log(`property ${prop} changed from ${serverConfig[prop]} to ${answers[prop]}`);
|
|
128
|
+
serverConfig[prop] = answers[prop];
|
|
129
|
+
if (prop !== 'password' || isPwdNonEmpty) {
|
|
130
|
+
bWriteUpdate = true;
|
|
131
|
+
}
|
|
132
|
+
if (prop === 'server') {
|
|
133
|
+
data[SERVER_CONFIG][isLaunchPad ? LP_SERVER_REST_URL : SERVER_REST_URL] = answers.server;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
authOK = await generateAccessToken(serverConfig);
|
|
140
|
+
} catch (e) {
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
delete serverConfig.serverType;
|
|
144
|
+
delete serverConfig.server;
|
|
145
|
+
|
|
146
|
+
if (authOK & bWriteUpdate) {
|
|
147
|
+
// Don't write password value (unless it already had a value)
|
|
148
|
+
if (!isPwdNonEmpty) {
|
|
149
|
+
serverConfig['password'] = '';
|
|
150
|
+
}
|
|
151
|
+
console.log(`${chalk.green('Writing updated config...')}`);
|
|
152
|
+
let updCfg = null;
|
|
153
|
+
try {
|
|
154
|
+
updCfg = JSON.stringify(data, null, 2);
|
|
155
|
+
// console.log(`updated config: ${updCfg}`);
|
|
156
|
+
fs.writeFileSync(pegaConfigJsonPath, updCfg, err => {
|
|
157
|
+
if (err) throw err;
|
|
158
|
+
});
|
|
159
|
+
} catch (e) {
|
|
160
|
+
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
process.exit(1);
|
|
165
|
+
|
|
90
166
|
};
|
|
@@ -45,7 +45,12 @@ const copyComponentTemplate = async options => {
|
|
|
45
45
|
}
|
|
46
46
|
else {
|
|
47
47
|
return copy(options.templateDirectoryConstellation, options.targetDirectoryConstellation, {
|
|
48
|
-
clobber: false
|
|
48
|
+
clobber: false,
|
|
49
|
+
filter: (fileName) => {
|
|
50
|
+
// filter out the file config.json or config.json.mustache
|
|
51
|
+
if (fileName.indexOf("config.json") >= 0) return false;
|
|
52
|
+
else return true;
|
|
53
|
+
}
|
|
49
54
|
});
|
|
50
55
|
}
|
|
51
56
|
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import {{COMPONENT_CLASS_NAME}} from './index.tsx';
|
|
3
|
+
import { pyReviewRaw } from './mock.stories';
|
|
4
|
+
import { TextField } from '@material-ui/core';
|
|
5
|
+
import MuiPhoneNumber from 'material-ui-phone-number';
|
|
6
|
+
import { KeyboardDatePicker, MuiPickersUtilsProvider } from '@material-ui/pickers';
|
|
7
|
+
import DayjsUtils from '@date-io/dayjs';
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: '{{COMPONENT_CLASS_NAME}}',
|
|
11
|
+
component: {{COMPONENT_CLASS_NAME}}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const renderField = resolvedProps => {
|
|
15
|
+
const { displayMode, value = '', label = '', onChange} = resolvedProps;
|
|
16
|
+
|
|
17
|
+
const variant = displayMode === 'LABELS_LEFT' ? 'inline' : 'stacked';
|
|
18
|
+
let val = '';
|
|
19
|
+
if (label === 'Service Date')
|
|
20
|
+
val = <MuiPickersUtilsProvider utils={DayjsUtils}><KeyboardDatePicker
|
|
21
|
+
variant='inline'
|
|
22
|
+
inputVariant='outlined'
|
|
23
|
+
placeholder='mm/dd/yyyy'
|
|
24
|
+
fullWidth
|
|
25
|
+
format='MM/DD/YYYY'
|
|
26
|
+
mask='__/__/____'
|
|
27
|
+
size='small'
|
|
28
|
+
label={label}
|
|
29
|
+
value={value || null}
|
|
30
|
+
onChange={onChange}
|
|
31
|
+
/>
|
|
32
|
+
</MuiPickersUtilsProvider>
|
|
33
|
+
|
|
34
|
+
{{! pick new delimiteres for mustache }}
|
|
35
|
+
{{=<% %>=}}
|
|
36
|
+
|
|
37
|
+
if (label === 'Email')
|
|
38
|
+
val = <TextField type='email' value={value} size='small' variant='outlined' style={{ fontSize: '14px' }} label={label} onChange={onChange}></TextField>;
|
|
39
|
+
|
|
40
|
+
if (label === 'First Name' || label === 'Last Name' || label === 'Middle Name')
|
|
41
|
+
val = <TextField value={value} size='small' variant='outlined' style={{ fontSize: '14px' }} label={label} onChange={onChange}></TextField>;
|
|
42
|
+
|
|
43
|
+
if (label === 'Phone Number')
|
|
44
|
+
val = <MuiPhoneNumber value={value} variant='outlined' size='small' style={{ fontSize: '14px' }} defaultCountry='us' label={label} onChange={onChange}></MuiPhoneNumber>;
|
|
45
|
+
|
|
46
|
+
<%={{ }}=%> {{! revert delimiteres for mustache }}
|
|
47
|
+
|
|
48
|
+
if (variant === 'inline') {
|
|
49
|
+
val = value || <span aria-hidden='true'>––</span>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return val;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const Base{{COMPONENT_CLASS_NAME}} = () => {
|
|
56
|
+
const [firstName, setFirstName] = useState('John');
|
|
57
|
+
const [middleName, setMiddleName] = useState('');
|
|
58
|
+
const [lastName, setLastName] = useState('Joe');
|
|
59
|
+
const [phone, setPhone] = useState('+16397975093');
|
|
60
|
+
const [serviceDate, setServiceDate] = useState('2023-01-25');
|
|
61
|
+
const [email, setEmail] = useState('john@doe.com');
|
|
62
|
+
const regionChildrenResolved = [
|
|
63
|
+
{
|
|
64
|
+
readOnly: undefined,
|
|
65
|
+
value: firstName,
|
|
66
|
+
label: 'First Name',
|
|
67
|
+
hasSuggestions: false,
|
|
68
|
+
onChange: val => {
|
|
69
|
+
setFirstName(val.target.value);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
readOnly: undefined,
|
|
74
|
+
value: middleName,
|
|
75
|
+
label: 'Middle Name',
|
|
76
|
+
hasSuggestions: false,
|
|
77
|
+
onChange: val => {
|
|
78
|
+
setMiddleName(val.target.value);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
readOnly: undefined,
|
|
83
|
+
value: lastName,
|
|
84
|
+
label: 'Last Name',
|
|
85
|
+
hasSuggestions: false,
|
|
86
|
+
onChange: val => {
|
|
87
|
+
setLastName(val.target.value);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
readOnly: undefined,
|
|
92
|
+
value: email,
|
|
93
|
+
label: 'Email',
|
|
94
|
+
hasSuggestions: false,
|
|
95
|
+
onChange: val => {
|
|
96
|
+
setEmail(val.target.value);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
readOnly: undefined,
|
|
101
|
+
value: phone,
|
|
102
|
+
label: 'Phone Number',
|
|
103
|
+
datasource: {
|
|
104
|
+
fields: {
|
|
105
|
+
value: undefined
|
|
106
|
+
},
|
|
107
|
+
source: [
|
|
108
|
+
{
|
|
109
|
+
value: '+1'
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
value: '+91'
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
value: '+48'
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
value: '+44'
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
hasSuggestions: false,
|
|
123
|
+
onChange: val => {
|
|
124
|
+
setPhone(val);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
readOnly: undefined,
|
|
129
|
+
value: serviceDate,
|
|
130
|
+
label: 'Service Date',
|
|
131
|
+
hasSuggestions: false,
|
|
132
|
+
onChange: date => {
|
|
133
|
+
const changeValue = date && date.isValid() ? date.toISOString() : null;
|
|
134
|
+
setServiceDate(changeValue);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
}
|
|
138
|
+
];
|
|
139
|
+
const props = {
|
|
140
|
+
template: 'DefaultForm',
|
|
141
|
+
getPConnect: () => {
|
|
142
|
+
return {
|
|
143
|
+
getChildren: () => {
|
|
144
|
+
return pyReviewRaw.children;
|
|
145
|
+
},
|
|
146
|
+
createComponent: config => {
|
|
147
|
+
switch (config.config.value) {
|
|
148
|
+
case '@P .FirstName':
|
|
149
|
+
return renderField(regionChildrenResolved[0]);
|
|
150
|
+
case '@P .MiddleName':
|
|
151
|
+
return renderField(regionChildrenResolved[1]);
|
|
152
|
+
case '@P .LastName':
|
|
153
|
+
return renderField(regionChildrenResolved[2]);
|
|
154
|
+
case '@P .Email':
|
|
155
|
+
return renderField(regionChildrenResolved[3]);
|
|
156
|
+
case '@P .PhoneNumber':
|
|
157
|
+
return renderField(regionChildrenResolved[4]);
|
|
158
|
+
case '@P .ServiceDate':
|
|
159
|
+
return renderField(regionChildrenResolved[5]);
|
|
160
|
+
default:
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const regionAChildren = pyReviewRaw.children[0].children.map(child => {
|
|
169
|
+
return props.getPConnect().createComponent(child);
|
|
170
|
+
});
|
|
171
|
+
const regionBChildren = pyReviewRaw.children[1].children.map(child => {
|
|
172
|
+
return props.getPConnect().createComponent(child);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<>
|
|
177
|
+
<{{COMPONENT_CLASS_NAME}} {...props}>
|
|
178
|
+
{regionAChildren}
|
|
179
|
+
{regionBChildren}
|
|
180
|
+
</{{COMPONENT_CLASS_NAME}}>
|
|
181
|
+
</>
|
|
182
|
+
);
|
|
183
|
+
};
|