Skip to content

Commit

Permalink
feat: dataraptor assessment
Browse files Browse the repository at this point in the history
  • Loading branch information
AbhinavKumar-sf committed Nov 8, 2024
1 parent 07b4e66 commit c4086fd
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 90 deletions.
1 change: 1 addition & 0 deletions messages/assess.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"duplicatedCardName": "Duplicated Flex Card name",
"duplicatedDrName": "Duplicated DataRaptor name",
"duplicatedOSName": "Duplicated OmniScript name",
"duplicatedName": "Duplicated name",
"errorWhileActivatingOs": "Could not activate OmniScript / Integration Procedure: ",
"errorWhileActivatingCard": "Could not activate Card: ",
"errorWhileUploadingCard": "An error ocurred while uploading Card: ",
Expand Down
121 changes: 94 additions & 27 deletions src/migration/dataraptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
import { AnyJson } from '@salesforce/ts-types';
import DRBundleMappings from '../mappings/DRBundle';
import DRMapItemMappings from '../mappings/DRMapItem';
import { DebugTimer, QueryTools } from '../utils';
import { DebugTimer, oldNew, QueryTools } from '../utils';
import { NetUtils } from '../utils/net';
import { BaseMigrationTool } from './base';
import { MigrationResult, MigrationTool, ObjectMapping, TransformData, UploadRecordResult } from './interfaces';
import { DataRaptorAssessmentInfo } from '../../src/utils';

import { getAllFunctionMetadata, getReplacedString } from '../utils/formula/FormulaUtil';
import {
getAllFunctionMetadata,
getReplacedString,
populateRegexForFunctionMetadata,
} from '../utils/formula/FormulaUtil';
import { StringVal } from '../utils/StringValue/stringval';

export class DataRaptorMigrationTool extends BaseMigrationTool implements MigrationTool {
static readonly DRBUNDLE_NAME = 'DRBundle__c';
Expand Down Expand Up @@ -183,10 +188,25 @@ export class DataRaptorMigrationTool extends BaseMigrationTool implements Migrat
};
}

private async getAllDRToItemsMap(): Promise<Map<string, AnyJson[]>> {
const drToItemsMap = new Map<string, AnyJson[]>();
const drItems = await this.getAllItems();
for (const drItem of drItems) {
const drName = drItem['Name'];
if (drToItemsMap.has(drName)) {
drToItemsMap.get(drName).push(drItem);
} else {
drToItemsMap.set(drName, [drItem]);
}
}
return drToItemsMap;
}

public async assess(): Promise<DataRaptorAssessmentInfo[]> {
try {
DebugTimer.getInstance().lap('Query data raptors');
const dataRaptors = await this.getAllDataRaptors();

const dataRaptorAssessmentInfos = this.processDRComponents(dataRaptors);
/* this.ux.log('dataRaptorAssessmentInfos');
this.ux.log(dataRaptorAssessmentInfos.toString()); */
Expand All @@ -201,40 +221,73 @@ export class DataRaptorMigrationTool extends BaseMigrationTool implements Migrat
const dataRaptorAssessmentInfos: DataRaptorAssessmentInfo[] = [];
// Query all the functionMetadata with all required fields
const functionDefinitionMetadata = await getAllFunctionMetadata(this.namespace, this.connection);
populateRegexForFunctionMetadata(functionDefinitionMetadata);
const existingDataRaptorNames = new Set<string>();
const dataRaptorItemsMap = await this.getAllDRToItemsMap();

// Now process each OmniScript and its elements
for (const dataRaptor of dataRaptors) {
if (dataRaptor[this.namespacePrefix + 'Type__c'] === 'Migration') continue;
const drName = dataRaptor['Name'];
// Await here since processOSComponents is now async
this.ux.log(dataRaptor['Name']);
this.ux.log(dataRaptor[this.namespacePrefix + 'Formula__c']);
var customFunctionString = '';
if (dataRaptor[this.namespacePrefix + 'Formula__c'] != null) {
this.ux.log('formula');
customFunctionString =
'Original Formula :' + dataRaptor[this.namespacePrefix + 'Formula__c'] + '\n\n' + 'Replaced Formula :Formula';
try {
customFunctionString +=
'Replaced Formula :Formula \n\n' +
getReplacedString(
this.namespacePrefix,
dataRaptor[this.namespacePrefix + 'Formula__c'],
functionDefinitionMetadata
);
} catch (ex) {
this.logger.error(JSON.stringify(ex));
console.log(
"There was some problem while updating the formula syntax, please check the all the formula's syntax once : " +
dataRaptor[this.namespacePrefix + 'Formula__c']
);
}
this.ux.log(drName);
const warnings: string[] = [];
const existingDRNameVal = new StringVal(drName, 'name');

if (!existingDRNameVal.isNameCleaned()) {
warnings.push(
this.messages.getMessage('changeMessage', [
existingDRNameVal.type,
existingDRNameVal.val,
existingDRNameVal.cleanName(),
])
);
}
if (existingDataRaptorNames.has(existingDRNameVal.cleanName())) {
warnings.push(this.messages.getMessage('duplicatedName') + ' ' + existingDRNameVal.cleanName());
} else {
existingDataRaptorNames.add(existingDRNameVal.cleanName());
}
const apexDependencies = [];
if (dataRaptor[this.namespacePrefix + 'CustomInputClass__c']) {
apexDependencies.push(dataRaptor[this.namespacePrefix + 'CustomInputClass__c']);
}
if (dataRaptor[this.namespacePrefix + 'CustomOutputClass__c']) {
apexDependencies.push(dataRaptor[this.namespacePrefix + 'CustomOutputClass__c']);
}

const formulaChanges: oldNew[] = [];
const drItems = dataRaptorItemsMap.get(drName);
if (drItems) {
for (const drItem of drItems) {
// this.ux.log(dataRaptor[this.namespacePrefix + 'Formula__c']);
const formula = drItem[this.namespacePrefix + 'Formula__c'];
if (formula) {
try {
const newFormula = getReplacedString(this.namespacePrefix, formula, functionDefinitionMetadata);
if (newFormula !== formula) {
formulaChanges.push({
old: formula,
new: newFormula,
});
}
} catch (ex) {
this.logger.error(JSON.stringify(ex));
console.log(
"There was some problem while updating the formula syntax, please check the all the formula's syntax once : " +
formula
);
}
}
}
}
const dataRaptorAssessmentInfo: DataRaptorAssessmentInfo = {
name: dataRaptor['Name'],
customFunction: customFunctionString,
name: existingDRNameVal.val,
id: dataRaptor['Id'],
formulaChanges: formulaChanges,
infos: [],
warnings: [],
apexDependencies: apexDependencies,
warnings: warnings,
};
dataRaptorAssessmentInfos.push(dataRaptorAssessmentInfo);
}
Expand Down Expand Up @@ -263,6 +316,20 @@ export class DataRaptorMigrationTool extends BaseMigrationTool implements Migrat
);
}

/*
private async getAllItemsForDataRaptorByName(drName: string): Promise<AnyJson[]> {
const filters = new Map<string, any>();
//Query all Elements
return await QueryTools.queryWithFilter(
this.connection,
this.namespace,
DataRaptorMigrationTool.DRMAPITEM_NAME,
this.getDRMapItemFields(),
filters.set('Name', drName)
);
}
*/

// Get All Items for one DataRaptor
private async getItemsForDataRaptor(
dataRaptorItems: AnyJson[],
Expand Down
8 changes: 7 additions & 1 deletion src/migration/omniscript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,12 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
const lwcName = propertySet['lwcName'];
dependenciesLWC.push({ name: lwcName, location: nameVal });
}
// To fetch custom overrides
if (propertySet['lwcComponentOverride']) {
const nameVal = `${elemName}`;
const lwcName = propertySet['lwcComponentOverride'];
dependenciesLWC.push({ name: lwcName, location: nameVal });
}
}

const omniProcessType = omniscript[this.namespacePrefix + 'IsProcedure__c']
Expand Down Expand Up @@ -325,7 +331,7 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
);
}
if (existingOmniscriptNames.has(recordName)) {
warnings.push(this.messages.getMessage('duplicatedName') + recordName);
warnings.push(this.messages.getMessage('duplicatedName') + ' ' + recordName);
} else {
existingOmniscriptNames.add(recordName);
}
Expand Down
6 changes: 3 additions & 3 deletions src/migration/related/ApexMigration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class ApexMigration extends BaseRelatedObjectMigration implements Related
const pwd = shell.pwd();
shell.cd(this.projectPath);
const targetOrg: Org = this.org;
sfProject.retrieve(APEXCLASS, targetOrg.getUsername());
// sfProject.retrieve(APEXCLASS, targetOrg.getUsername());
const apexAssessmentInfos = this.processApexFiles(this.projectPath);
sfProject.deploy(APEXCLASS, targetOrg.getUsername());
shell.cd(pwd);
Expand All @@ -60,8 +60,8 @@ export class ApexMigration extends BaseRelatedObjectMigration implements Related
public assess(): ApexAssessmentInfo[] {
const pwd = shell.pwd();
shell.cd(this.projectPath);
const targetOrg: Org = this.org;
sfProject.retrieve(APEXCLASS, targetOrg.getUsername());
// const targetOrg: Org = this.org;
// sfProject.retrieve(APEXCLASS, this.org.getUsername());
const apexAssessmentInfos = this.processApexFiles(this.projectPath);
shell.cd(pwd);
return apexAssessmentInfos;
Expand Down
2 changes: 1 addition & 1 deletion src/migration/related/LwcMigration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class LwcMigration extends BaseRelatedObjectMigration implements RelatedO
const type = 'assessment';
const pwd = shell.pwd();
shell.cd(this.projectPath);
sfProject.retrieve(LWCTYPE, this.org.getUsername());
// sfProject.retrieve(LWCTYPE, this.org.getUsername());
const filesMap = this.processLwcFiles(this.projectPath);
shell.cd(pwd);
return this.processFiles(filesMap, type);
Expand Down
12 changes: 8 additions & 4 deletions src/utils/formula/FormulaUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,21 @@ export async function getAllFunctionMetadata(namespace: string, connection: Conn
return await QueryTools.queryAll(connection, namespace, 'FunctionDefinition__mdt', getFunctionDefinitionFields());
}

export function populateRegexForFunctionMetadata(functionDefinitionMetadata: AnyJson[]) {
functionDefinitionMetadata.forEach((functionDef) => {
functionDef['regex'] = new RegExp('\\b' + functionDef['DeveloperName'] + '\\b', 'g');
});
}
export function getReplacedString(
namespacePrefix: string,
inputString: string,
functionDefinitionMetadata: AnyJson[]
): string {
let formulaSyntax = inputString;
for (let functionDefMd of functionDefinitionMetadata) {
const FormulaName = functionDefMd['DeveloperName'];
const regExStr = new RegExp('\\b' + FormulaName + '\\b', 'g');
const numberOfOccurances: number =
formulaSyntax.match(regExStr) !== null ? formulaSyntax.match(regExStr).length : 0;
const regExStr = functionDefMd['regex'];
const match = formulaSyntax.match(regExStr);
const numberOfOccurances: number = match !== null ? match.length : 0;
if (numberOfOccurances > 0) {
for (var count: number = 1; count <= numberOfOccurances; count++) {
formulaSyntax = getReplacedformulaString(
Expand Down
8 changes: 7 additions & 1 deletion src/utils/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,11 @@ export interface FlexCardAssessmentInfo {

export interface DataRaptorAssessmentInfo {
name: string;
customFunction: string;
id: string;
formulaChanges: oldNew[];
infos: string[];
warnings: string[];
apexDependencies: string[];
}

export interface OmniAssessmentInfo {
Expand Down Expand Up @@ -124,3 +125,8 @@ export interface nameLocation {
name: string;
location: string;
}

export interface oldNew {
old: string;
new: string;
}
68 changes: 68 additions & 0 deletions src/utils/resultsbuilder/DRAssessmentReporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { DataRaptorAssessmentInfo } from '../interfaces';
import { reportingHelper } from './reportingHelper';

export class DRAssessmentReporter {
public static generateDRAssesment(
dataRaptorAssessmentInfos: DataRaptorAssessmentInfo[],
instanceUrl: string
): string {
let tableBody = '';
tableBody += '<div class="slds-text-heading_large">Data Raptor Components Assessment</div>';
for (const dr of dataRaptorAssessmentInfos) {
const row = `
<tr class="slds-hint_parent">
<td style="word-wrap: break-word; white-space: normal; max-width: 200px;">
<div class="slds-truncate" title="${dr.name}">${dr.name}</div>
</td>
<td style="word-wrap: break-word; white-space: normal; max-width: 100px;">
<div class="slds-truncate" title="${dr.id}">
<a href="${instanceUrl}/${dr.id}">${dr.id}</div>
</td>
<td style="word-wrap: break-word; white-space: normal; max-width: 60%; overflow: hidden;">
${reportingHelper.convertToBuletedList(dr.warnings)}
</td>
<td style="word-wrap: break-word; white-space: normal; max-width: 200px;">
<div> ${reportingHelper.decorateChanges(dr.formulaChanges, 'Formula')} </div>
</td>
<td style="word-wrap: break-word; white-space: normal; max-width: 60%; overflow: hidden;">
${reportingHelper.convertToBuletedList(dr.apexDependencies)}
</td>
</tr>`;
tableBody += row;
}

return DRAssessmentReporter.getDRAssessmentReport(tableBody);
}

private static getDRAssessmentReport(tableContent: string): string {
const tableBody = `
<div style="margin-block:15px">
<table style="width: 100%; table-layout: auto;" class="slds-table slds-table_cell-buffer slds-table_bordered slds-table_striped slds-table_col-bordered" aria-label="Results for Data Raptor updates">
<thead>
<tr class="slds-line-height_reset">
<th class="" scope="col" style="width: 20%; word-wrap: break-word; white-space: normal; text-align: left;">
<div class="slds-truncate" title="Name">Name</div>
</th>
<th class="" scope="col" style="width: 10%; word-wrap: break-word; white-space: normal; text-align: left;">
<div class="slds-truncate" title="ID">ID</div>
</th>
<th class="" scope="col" style="width: 20%; word-wrap: break-word; white-space: normal; text-align: left;">
<div class="slds-truncate" title="Summary">Summary</div>
</th>
<th class="" scope="col" style="width: 20%; word-wrap: break-word; white-space: normal; text-align: left;">
<div class="slds-truncate" title="Custom Function Change">Custom Function Changes</div>
</th>
<th class="" scope="col" style="width: 20%; word-wrap: break-word; white-space: normal; text-align: left;">
<div class="slds-truncate" title="Apex dependencies">Apex dependencies</div>
</th>
</tr>
</thead>
<tbody>
${tableContent}
</tbody>
</table>
</div>`;
return tableBody;
}
}
Loading

0 comments on commit c4086fd

Please sign in to comment.