@pega/custom-dx-components
Version:
Utility for building custom UI components
301 lines (265 loc) • 10.1 kB
JavaScript
import fs from 'fs';
import path from 'path';
import chalk from 'chalk';
import fetch from 'node-fetch';
import { join } from 'path';
import { LIST_COMPONENT_SERVICE_REST_ENDPOINT, LP_LIST_COMPONENT_SERVICE_REST_ENDPOINT, TOKEN_PATH, COMPONENT_SCHEMA, TASKS_CONFIG_JSON_FILENAME, COMPONENTS_DIRECTORY_PATH, COMPONENTS_PATH } from '../../constants.js';
import { constructCompleteUrl, getComponents, getPegaServerConfig, getHttpsAgent, addDebugLog, getLibraryBased, getComponentsConfigs, getConfigDefaults } from '../../util.js';
export const SOURCE_OF_COMPONENT_TYPES = {
SERVER: 'Server',
LOCAL: 'Local'
};
export const getListComponentsQuestions = async (options) => {
addDebugLog("getListComponentsQuestions", "", "");
const defaultPegaServerConfig = await getPegaServerConfig();
return [
{
name: 'sourceOfComponents',
type: 'rawlist',
message: 'List components from Server or Local ?',
choices: Object.values(SOURCE_OF_COMPONENT_TYPES),
default: defaultPegaServerConfig.sourceOfComponents,
when() {
return !options.params[3];
}
}
];
};
export const getLaunchPadFilterQuestions = async () => {
addDebugLog("getLaunchPadFilterQuestions", "", "");
const defaultPegaServerConfig = await getPegaServerConfig();
const currentDirectory = process.cwd();
const pegaConfigJsonPath = join(currentDirectory, TASKS_CONFIG_JSON_FILENAME);
let data = fs.readFileSync(pegaConfigJsonPath, { encoding: 'utf8' });
data = data && JSON.parse(data);
if (!data[COMPONENTS_DIRECTORY_PATH]) {
console.error(
`${chalk.red.bold('ERROR')} Could not able find components directory path in config.json`
);
process.exit(1);
}
const componentData = data[COMPONENTS_PATH];
let { library } = componentData;
let { organization } = JSON.parse(fs.readFileSync(path.resolve('package.json'), 'utf8'));
return [
{
name: 'organization',
message: 'Enter component organization (required)',
default: organization,
validate: value => {
if (value) {
return true;
}
return 'Please provide value for organization';
}
},
{
name: 'library',
message: 'Enter library name (required)',
default: library,
validate: value => {
if (value) {
return true;
}
return 'Please provide value for library';
}
}
];
}
export const listLocalComponents = async (sourceOfComponents) => {
addDebugLog("listLocalComponents", `sourceOfComponents: ${sourceOfComponents}`, "");
const isLibraryBased = getLibraryBased();
if (isLibraryBased) {
const defConfig = getConfigDefaults();
const data = await getComponentsConfigs();
// get built on from first component if exists
let builtOn = "(date unavailable)";
if (data[0] && data[0].buildDate) {
builtOn = data[0].buildDate;
}
if (data.length === 0) {
console.log(chalk.bold.redBright(`No custom components in ${sourceOfComponents}`));
process.exit();
}
let libData = data.map((component) => ( {'Component': component.name, 'Label': component.label, 'Version': component.version, 'Type': component.type, 'Sub Type' : component.subtype}));
console.log(chalk.bold.blueBright(`\nList of ${defConfig.library}:${defConfig.buildVersion} components.`));
console.table(libData, ['Component', 'Label', 'Version', 'Type', 'Sub Type']);
}
else {
let localComponents = await getComponents();
localComponents = localComponents.map((name) => ({ 'Rule name': name }));
if (localComponents.length > 0) {
console.log(chalk.bold.blueBright(`List of custom components in ${sourceOfComponents}`));
console.table(localComponents, ['Rule name']);
} else {
console.log(chalk.bold.redBright(`No custom components in ${sourceOfComponents}`));
}
}
};
async function fetchComponentsFromInfinity(apiUrl, headers) {
addDebugLog("fetchComponentsFromInfinity", `apiUrl: ${apiUrl}`, "");
const serverConfig = await getPegaServerConfig();
return new Promise((resolve, reject) => {
let status = 500;
fetch(apiUrl, {
method: 'GET',
agent: getHttpsAgent(serverConfig),
headers
})
.then((response) => {
status = response.status;
if (status === 401) {
throw new Error('Error occurred in authentication. Please regenerate using authenticate');
}
else if (status === 404){
throw new Error('404: Server resource not found');
}
else if (status === 405){
throw new Error('405: Server method not allowed');
}
else if (status === 408){
throw new Error('408: Server timed out');
}
return response.json();
})
.then((resp) => {
// const respData = JSON.parse(resp);
if (status === 401) {
throw new Error('Error occurred in authentication. Please regenerate using authenticate');
// console.log(accessTokenUri, refreshToken);
/* TODO - Handle refresh_token */
} else if (status === 200) {
resolve(resp);
} else {
throw new Error(`${resp.message}`);
}
})
// eslint-disable-next-line prefer-promise-reject-errors
.catch((e) => reject(`${chalk.bold.red(e)}`));
});
}
async function fetchComponentsFromLaunchpad(apiUrl, headers) {
addDebugLog("fetchComponentsFromLaunchpad", `apiUrl: ${apiUrl}`, "");
const serverConfig = await getPegaServerConfig();
// constructing urls for all type of components
const urls = COMPONENT_SCHEMA.type.map((type) => apiUrl.replace('{type}', type.value));
const statuses = [];
return new Promise((resolve, reject) => {
Promise.all(
urls.map(async (url) => {
return fetch(url, {
method: 'GET',
agent: getHttpsAgent(serverConfig),
headers
});
})
)
.then((responses) => {
return Promise.all(
responses.map((res) => {
statuses.push(res.status);
if (res.status === 401 || res.status === 503) {
// Finding a 503 response is sometimes being returned from Launchpad in expired authentication scenario
throw new Error('Authorization error. Please regenerate using authenticate');
} else if (res.ok) {
return res.json();
} else {
throw new Error(`Unexpected Error ${res.status} encountered. ${res.message}`);
}
})
);
})
.then((data) => {
const components = data.map((res) => res.components).flat();
resolve(components);
})
// eslint-disable-next-line prefer-promise-reject-errors
.catch((e) => reject(`${chalk.bold.red(e)}`));
});
}
export const getComponentsFromServer = async (library, organization) => {
addDebugLog("getComponentsFromServer", `library: ${library}, organization: ${organization}`, "");
const defaultPegaServerConfig = await getPegaServerConfig();
const isLaunchpad = defaultPegaServerConfig.serverType === 'launchpad';
const url = constructCompleteUrl(
defaultPegaServerConfig.server,
isLaunchpad ? LP_LIST_COMPONENT_SERVICE_REST_ENDPOINT : LIST_COMPONENT_SERVICE_REST_ENDPOINT
);
return new Promise((resolve, reject) => {
try {
fs.readFile(TOKEN_PATH, 'utf8', (err, data) => {
if (err) {
// eslint-disable-next-line prefer-promise-reject-errors
reject(`\n${chalk.bold.red('Error occurred in authentication. Please regenerate using authenticate')}`);
}
if (data) {
const { access_token: accessToken, token_type: tokenType } = JSON.parse(data);
const headers = {};
if (isLaunchpad) {
headers.cookie = `Pega-AAT=${accessToken}`;
fetchComponentsFromLaunchpad(url, headers)
.then((response) => {
response = response.filter(component => (component.library === library || library === "*" ) && (component.organization === organization || organization === "*"));
resolve(response); }
)
.catch((e) => reject(e));
} else {
headers.Authorization = `${tokenType} ${accessToken}`;
fetchComponentsFromInfinity(url, headers)
.then((response) => resolve(response))
.catch((e) => reject(e));
}
}
});
} catch (error) {
console.log(`\n${chalk.bold.red(error)}`);
// eslint-disable-next-line prefer-promise-reject-errors
reject(`${chalk.bold.red(error)}`);
}
});
};
export const displayServerComponents = async (data) => {
addDebugLog("displayServerComponents", "", "");
const defaultPegaServerConfig = await getPegaServerConfig();
const isLaunchpad = defaultPegaServerConfig.serverType === 'launchpad';
let list;
if (isLaunchpad) {
list = data;
} else {
try {
if (typeof data === 'object') {
list = data.pxResults;
} else {
list = JSON.parse(data).pxResults;
}
} catch (ex) {
/* empty */
}
}
/**
* TODO: Need to modify the components list mapping code to support Launchpad components
*/
const componentList = list?.map(({ label, pyRuleSet, pyRuleSetVersion, type }) => {
if (isLaunchpad) {
return {
'Component Name': label,
Type: type
};
}
return {
'Rule name': label,
'Ruleset name': pyRuleSet,
'Ruleset version': pyRuleSetVersion
};
});
if (componentList && componentList.length > 0) {
console.log(chalk.bold.blueBright(`List of custom components in ${defaultPegaServerConfig.server}`));
if (isLaunchpad) {
console.table(componentList, ['Component Name', 'Type']);
} else {
console.table(componentList, ['Rule name', 'Ruleset name', 'Ruleset version']);
}
} else {
console.log(chalk.bold.redBright(`No custom components in ${defaultPegaServerConfig.server}`));
}
};