Skip to content

Commit d66fc27

Browse files
committed
Org preference to disable rollback flags and test
1 parent 71e5d7d commit d66fc27

File tree

5 files changed

+360
-12
lines changed

5 files changed

+360
-12
lines changed

src/commands/omnistudio/migration/assess.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ export default class Assess extends OmniStudioBaseCommand {
9494
flexCardAssessmentInfos,
9595
omniAssessmentInfo,
9696
};
97-
await AssessmentReporter.generate(assesmentInfo, conn.instanceUrl);
97+
98+
await AssessmentReporter.generate(assesmentInfo, conn.instanceUrl, conn, orgs);
9899
return assesmentInfo;
99100
}
100101
}

src/commands/omnistudio/migration/migrate.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { Logger } from '../../../utils/logger';
2323
import OmnistudioRelatedObjectMigrationFacade from '../../../migration/related/OmnistudioRelatedObjectMigrationFacade';
2424
import { generatePackageXml } from '../../../utils/generatePackageXml';
2525
import { OmnistudioOrgDetails, OrgUtils } from '../../../utils/orgUtils';
26+
import { OrgPreferences } from '../../../utils/orgpreferences';
2627

2728
// Initialize Messages with the current plugin directory
2829
Messages.importMessagesDirectory(__dirname);
@@ -68,6 +69,7 @@ export default class Migrate extends OmniStudioBaseCommand {
6869

6970
Logger.initialiseLogger(this.ux, this.logger);
7071
this.logger = Logger.logger;
72+
7173
// this.org is guaranteed because requiresUsername=true, as opposed to supportsUsername
7274
const conn = this.org.getConnection();
7375
conn.setApiVersion(apiVersion);
@@ -84,6 +86,17 @@ export default class Migrate extends OmniStudioBaseCommand {
8486
return;
8587
}
8688

89+
// Enable Omni preferences
90+
try {
91+
this.ux.log('Enabling Omni preferences...');
92+
await OrgPreferences.enableOmniPreferences(conn);
93+
this.ux.log('Omni preferences enabled successfully.');
94+
} catch (error) {
95+
const errMsg = error instanceof Error ? error.message : String(error);
96+
this.ux.log(`Error: Could not enable Omni preferences: ${errMsg}`);
97+
throw error;
98+
}
99+
87100
// Let's time every step
88101
DebugTimer.getInstance().start();
89102
let projectPath: string;

src/utils/orgpreferences.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { Connection } from '@salesforce/core';
2+
3+
/**
4+
* Interface representing the metadata structure for OmniStudio settings
5+
*
6+
* @interface OmniStudioSettingsMetadata
7+
* @property {string} fullName - The full name of the OmniStudio settings
8+
* @property {boolean} disableRollbackFlagsPref - Flag to disable rollback preferences
9+
*/
10+
interface OmniStudioSettingsMetadata {
11+
fullName: string;
12+
disableRollbackFlagsPref: boolean;
13+
}
14+
15+
/**
16+
* Interface representing the structure of query results from OmniInteractionConfig
17+
*
18+
* @interface QueryResult
19+
* @property {string} DeveloperName - Name of the configuration
20+
* @property {string} Value - Value of the configuration
21+
* @property {number} totalSize - Total number of records returned
22+
* @property {boolean} done - Whether the query is complete
23+
* @property {Array<{attributes: {type: string, url: string}, DeveloperName: string, Value: string}>} records - Array of query result records
24+
*/
25+
interface QueryResult {
26+
DeveloperName: string;
27+
Value: string;
28+
totalSize: number;
29+
done: boolean;
30+
records: Array<{
31+
attributes: {
32+
type: string;
33+
url: string;
34+
};
35+
DeveloperName: string;
36+
Value: string;
37+
}>;
38+
}
39+
40+
/**
41+
* Class to manage OmniStudio organization preferences
42+
*
43+
* @class OrgPreferences
44+
* @description Provides functionality to enable OmniStudio preferences and check rollback flags
45+
*/
46+
export class OrgPreferences {
47+
/**
48+
* List of rollback flags to check in OmniInteractionConfig
49+
*
50+
* @private
51+
* @static
52+
* @readonly
53+
* @type {string[]}
54+
*/
55+
private static readonly ROLLBACK_FLAGS: string[] = ['RollbackIPChanges', 'RollbackDRChanges', 'RollbackOSChanges'];
56+
57+
/**
58+
* Enables the disableRollbackFlagsPref setting in OmniStudio
59+
*
60+
* @public
61+
* @static
62+
* @async
63+
* @param {Connection} connection - Salesforce connection instance
64+
* @throws {Error} If enabling the preference fails
65+
* @returns {Promise<void>}
66+
*/
67+
public static async enableOmniPreferences(connection: Connection): Promise<void> {
68+
try {
69+
await connection.metadata.update('OmniStudioSettings', [
70+
{
71+
fullName: 'OmniStudio',
72+
disableRollbackFlagsPref: true,
73+
} as OmniStudioSettingsMetadata,
74+
]);
75+
} catch (error) {
76+
throw new Error(
77+
`Failed to enable disableRollbackFlagsPref: ${error instanceof Error ? error.message : String(error)}`
78+
);
79+
}
80+
}
81+
82+
/**
83+
* Checks which rollback flags are enabled in OmniInteractionConfig
84+
*
85+
* @public
86+
* @static
87+
* @async
88+
* @param {Connection} connection - Salesforce connection instance
89+
* @throws {Error} If checking rollback flags fails
90+
* @returns {Promise<string[]>} Array of enabled rollback flag names
91+
*/
92+
public static async checkRollbackFlags(connection: Connection): Promise<string[]> {
93+
try {
94+
const result = await connection.query<QueryResult>(
95+
`SELECT DeveloperName, Value FROM OmniInteractionConfig WHERE DeveloperName IN ('${this.ROLLBACK_FLAGS.join(
96+
"','"
97+
)}')`
98+
);
99+
const enabledFlags: string[] = [];
100+
for (const record of result.records) {
101+
if (record.Value === 'true') {
102+
enabledFlags.push(record.DeveloperName);
103+
}
104+
}
105+
return enabledFlags;
106+
} catch (error) {
107+
throw new Error(`Failed to check rollback flags: ${error instanceof Error ? error.message : String(error)}`);
108+
}
109+
}
110+
}

src/utils/resultsbuilder/assessmentReporter.ts

Lines changed: 112 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
11
/* eslint-disable prettier/prettier */
22
/* eslint-disable @typescript-eslint/restrict-template-expressions */
33
import fs from 'fs';
4+
import path from 'path';
45
import open from 'open';
6+
import { Connection } from '@salesforce/core';
57
import {
68
ApexAssessmentInfo,
79
AssessmentInfo,
810
LWCAssessmentInfo,
9-
OmniAssessmentInfo,
1011
FlexCardAssessmentInfo,
1112
nameLocation,
1213
} from '../interfaces';
13-
import { OSAssesmentReporter } from './OSAssessmentReporter';
14+
import { OrgPreferences } from '../orgpreferences';
15+
import { ReportHeaderFormat } from '../reportGenerator/reportInterfaces';
16+
import { OmnistudioOrgDetails } from '../orgUtils';
17+
import { OSAssessmentReporter } from './OSAssessmentReporter';
1418
import { IPAssessmentReporter } from './IPAssessmentReporter';
1519
import { DRAssessmentReporter } from './DRAssessmentReporter';
1620

1721
export class AssessmentReporter {
18-
public static async generate(result: AssessmentInfo, instanceUrl: string): Promise<void> {
22+
public static async generate(
23+
result: AssessmentInfo,
24+
instanceUrl: string, connection: Connection,
25+
omnistudioOrgDetails: OmnistudioOrgDetails
26+
): Promise<void> {
1927
const basePath = process.cwd() + '/assessment_reports';
2028
fs.mkdirSync(basePath, { recursive: true });
2129
const omniscriptAssessmentFilePath = basePath + '/omniscript_assessment.html';
@@ -24,25 +32,28 @@ export class AssessmentReporter {
2432
const dataMapperAssessmentFilePath = basePath + '/datamapper_assessment.html';
2533
const apexAssessmentFilePath = basePath + '/apex_assessment.html';
2634
const lwcAssessmentFilePath = basePath + '/lwc_assessment.html';
35+
const rollbackFlagsReportPath = basePath + '/rollback_flags_report.html';
36+
const orgDetails: ReportHeaderFormat[] = this.formattedOrgDetails(omnistudioOrgDetails);
2737

2838
this.createDocument(
2939
omniscriptAssessmentFilePath,
30-
this.generateOmniAssesment(result.omniAssessmentInfo, instanceUrl)
40+
OSAssessmentReporter.generateOSAssesment(result.omniAssessmentInfo.osAssessmentInfos, instanceUrl, orgDetails)
3141
);
3242
this.createDocument(
3343
flexcardAssessmentFilePath,
3444
this.generateCardAssesment(result.flexCardAssessmentInfos, instanceUrl)
3545
);
3646
this.createDocument(
3747
integrationProcedureAssessmentFilePath,
38-
IPAssessmentReporter.generateIPAssesment(result.omniAssessmentInfo.ipAssessmentInfos, instanceUrl)
48+
IPAssessmentReporter.generateIPAssesment(result.omniAssessmentInfo.ipAssessmentInfos, instanceUrl, orgDetails)
3949
);
4050
this.createDocument(
4151
dataMapperAssessmentFilePath,
4252
DRAssessmentReporter.generateDRAssesment(result.dataRaptorAssessmentInfos, instanceUrl)
4353
);
4454
this.createDocument(apexAssessmentFilePath, this.generateApexAssesment(result.apexAssessmentInfos));
4555
this.createDocument(lwcAssessmentFilePath, this.generateLwcAssesment(result.lwcAssessmentInfos));
56+
4657
const nameUrls = [
4758
{
4859
name: 'omnscript assessment report',
@@ -69,7 +80,88 @@ export class AssessmentReporter {
6980
location: 'lwc_assessment.html',
7081
},
7182
];
83+
84+
// Check rollback flags
85+
const enabledFlags = await OrgPreferences.checkRollbackFlags(connection);
86+
if (enabledFlags.length > 0) {
87+
this.createDocument(rollbackFlagsReportPath, this.generateRollbackFlagsReport(enabledFlags));
88+
nameUrls.push({
89+
name: 'Rollback Flags Report',
90+
location: 'rollback_flags_report.html',
91+
});
92+
}
93+
94+
7295
await this.createMasterDocument(nameUrls, basePath);
96+
this.pushAssestUtilites('javascripts', basePath);
97+
this.pushAssestUtilites('styles', basePath);
98+
}
99+
100+
private static formattedOrgDetails(orgDetails: OmnistudioOrgDetails): ReportHeaderFormat[] {
101+
return [
102+
{
103+
key: 'Org Name',
104+
value: orgDetails.orgDetails.Name,
105+
},
106+
{
107+
key: 'Org Id',
108+
value: orgDetails.orgDetails.Id,
109+
},
110+
{
111+
key: 'Package Name',
112+
value: orgDetails.packageDetails[0].namespace,
113+
},
114+
{
115+
key: 'Data Model',
116+
value: orgDetails.dataModel,
117+
},
118+
{
119+
key: 'Assessment Date and Time',
120+
value: new Date() as unknown as string,
121+
},
122+
];
123+
}
124+
125+
/**
126+
* Copies `.js` and `.css` files from a source directory (based on `folderName`)
127+
* to a specified destination directory.
128+
*
129+
* @param folderName - The subdirectory under `/src/` where source asset files are located (e.g., `'javascripts'`, `'styles'`).
130+
* @param destDir - The absolute or relative path to the destination directory where the assets should be copied.
131+
*
132+
* @remarks
133+
* - If the destination directory does not exist, the method logs a warning and exits.
134+
* - Only `.js` and `.css` files are copied.
135+
* - The source files remain in place after copying.
136+
*/
137+
private static pushAssestUtilites(folderName: string, destDir: string): void {
138+
const sourceDir = path.join(process.cwd(), 'src', folderName);
139+
140+
if (!fs.existsSync(destDir)) {
141+
// Destination directory does not exist. Skipping file copy.
142+
return;
143+
}
144+
145+
fs.readdir(sourceDir, (readDirErr, files) => {
146+
if (readDirErr) {
147+
// Error reading source directory: readDirErr.message
148+
return;
149+
}
150+
151+
files.forEach((file) => {
152+
const ext = path.extname(file);
153+
if (ext === '.js' || ext === '.css') {
154+
const srcPath = path.join(sourceDir, file);
155+
const destPath = path.join(destDir, file);
156+
157+
fs.copyFile(srcPath, destPath, (copyErr) => {
158+
if (copyErr) {
159+
// Failed to copy file: copyErr.message
160+
}
161+
});
162+
}
163+
});
164+
});
73165
}
74166

75167
private static async createMasterDocument(reports: nameLocation[], basePath: string): Promise<void> {
@@ -195,11 +287,6 @@ export class AssessmentReporter {
195287
</div>`;
196288
return tableBody;
197289
}
198-
private static generateOmniAssesment(omniAssessmentInfo: OmniAssessmentInfo, instanceUrl: string): string {
199-
let htmlBody = '';
200-
htmlBody += '<br />' + OSAssesmentReporter.generateOSAssesment(omniAssessmentInfo.osAssessmentInfos, instanceUrl);
201-
return htmlBody;
202-
}
203290

204291
private static generateCardAssesment(flexCardAssessmentInfos: FlexCardAssessmentInfo[], instanceUrl: string): string {
205292
let tableBody = '';
@@ -246,7 +333,6 @@ export class AssessmentReporter {
246333
</head>
247334
<body>
248335
<div style="margin: 20px;">
249-
<div class="slds-text-heading_large">OmniStudio Migration Assessment </div>
250336
${resultsAsHtml}
251337
</div>
252338
</div>
@@ -311,4 +397,19 @@ export class AssessmentReporter {
311397
</div>`;
312398
return tableBody;
313399
}
400+
401+
private static generateRollbackFlagsReport(enabledFlags: string[]): string {
402+
return `
403+
<div class="slds-box slds-theme_warning" style="margin-bottom: 20px;">
404+
<div class="slds-text-heading_medium slds-m-bottom_small">⚠️ Warning: Rollback Flags Enabled</div>
405+
<p>The following rollback flags are currently enabled and will be disabled during migration:</p>
406+
<ul class="slds-m-top_small">
407+
${enabledFlags.map((flag) => `<li>${flag}</li>`).join('')}
408+
</ul>
409+
<p class="slds-m-top_small">
410+
<strong>Note:</strong> These flags will not be supported after migration. For assistance, please contact support.
411+
</p>
412+
</div>
413+
`;
414+
}
314415
}

0 commit comments

Comments
 (0)