Skip to content

Commit 1831cf4

Browse files
@W-19464598 - Omnistudio config tables cleanup for UseCase2 (#417)
1 parent 502bce2 commit 1831cf4

File tree

6 files changed

+701
-2
lines changed

6 files changed

+701
-2
lines changed

messages/migrate.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,5 +244,12 @@
244244
"customLabelAssessmentSummary": "Custom Label with same name and different value is already exist without namespace.",
245245
"generatedCustomLabelAssessmentReportPage": "Generated custom label assessment report page %s of %s with %s labels",
246246
"varDeclarationUpdated": "Variable initialization has been updated for target name",
247-
"migrationSuccessfulMessage": "Migration process for org %s is complete and reports are ready for review in the folder %s"
247+
"migrationSuccessfulMessage": "Migration process for org %s is complete and reports are ready for review in the folder %s",
248+
"metadataTablesAlreadyClean": "OmniStudio metadata tables are empty",
249+
"startingMetadataCleanup": "Initiated cleanup process for Omnistudio metadata tables.",
250+
"failedToCleanTables": "Table cleanup failed: %s",
251+
"errorCheckingMetadataTables": "Error checking Omnistudio metadata tables: %s",
252+
"metadataCleanupCompleted": "The Omnistudio metadata table cleanup process is complete. Total records cleaned: %s",
253+
"metadataCleanupConsentMessage": "By proceeding further, you hereby consent to clean up the Omnistudio metadata tables. Proceeding with the cleanup process will permanently delete all records from OmniUiCardConfig, OmniScriptConfig, OmniIntegrationProcConfig, and OmniDataTransformConfig tables. Do you want to proceed? [y/n]",
254+
"metadataCleanupConsentNotGiven": "You’ve not consented to proceed with the Omnistudio metadata table cleanup. We’ll not be able to proceed with the migration."
248255
}

src/commands/omnistudio/migration/migrate.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { YES_SHORT, YES_LONG, NO_SHORT, NO_LONG } from '../../../utils/projectPa
3131
import { PostMigrate } from '../../../migration/postMigrate';
3232
import { PreMigrate } from '../../../migration/premigrate';
3333
import { GlobalAutoNumberMigrationTool } from '../../../migration/globalautonumber';
34-
import { initializeDataModelService } from '../../../utils/dataModelService';
34+
import { initializeDataModelService, isStandardDataModel } from '../../../utils/dataModelService';
3535
import { NameMappingRegistry } from '../../../migration/NameMappingRegistry';
3636
import { ValidatorService } from '../../../utils/validatorService';
3737

@@ -127,6 +127,14 @@ export default class Migrate extends OmniStudioBaseCommand {
127127
const preMigrate: PreMigrate = new PreMigrate(namespace, conn, this.logger, messages, this.ux);
128128
const isExperienceBundleMetadataAPIProgramaticallyEnabled: { value: boolean } = { value: false };
129129

130+
// Handle config tables cleanup for standard data model migration
131+
if (isStandardDataModel()) {
132+
const isMetadataCleanupSuccess = await preMigrate.handleOmniStudioMetadataCleanup();
133+
if (!isMetadataCleanupSuccess) {
134+
return;
135+
}
136+
}
137+
130138
let actionItems = [];
131139

132140
let deploymentConfig = { autoDeploy: false, authKey: undefined };

src/migration/premigrate.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { OrgPreferences } from '../utils/orgPreferences';
66
import { askStringWithTimeout, PromptUtil } from '../utils/promptUtil';
77
import { YES_SHORT, YES_LONG, NO_SHORT, NO_LONG } from '../utils/projectPathUtil';
88
import { documentRegistry } from '../utils/constants/documentRegistry';
9+
import { OmniStudioMetadataCleanupService } from '../utils/config/OmniStudioMetadataCleanupService';
910
import { BaseMigrationTool } from './base';
1011

1112
const authEnvKey = 'OMA_AUTH_KEY';
@@ -109,6 +110,28 @@ export class PreMigrate extends BaseMigrationTool {
109110
return deploymentConfig;
110111
}
111112

113+
/**
114+
* Handles OmniStudio metadata tables cleanup with user consent
115+
*
116+
* @returns Promise<boolean> - true if cleanup was successful, false otherwise
117+
*/
118+
public async handleOmniStudioMetadataCleanup(): Promise<boolean> {
119+
const omniStudioMetadataCleanupService = new OmniStudioMetadataCleanupService(this.connection, this.messages);
120+
121+
if (await omniStudioMetadataCleanupService.hasCleanOmniStudioMetadataTables()) {
122+
Logger.logVerbose(this.messages.getMessage('metadataTablesAlreadyClean'));
123+
return true;
124+
}
125+
126+
const consent = await this.getMetadataCleanupConsent();
127+
128+
if (!consent) {
129+
Logger.error(this.messages.getMessage('metadataCleanupConsentNotGiven'));
130+
return false;
131+
}
132+
return await omniStudioMetadataCleanupService.cleanupOmniStudioMetadataTables();
133+
}
134+
112135
// This needs to be behind timeout
113136
private async getExpSiteMetadataEnableConsent(): Promise<boolean> {
114137
const question = this.messages.getMessage('consentForExperienceSites');
@@ -148,4 +171,39 @@ export class PreMigrate extends BaseMigrationTool {
148171
relatedObjects.splice(index, 1);
149172
}
150173
}
174+
175+
/**
176+
* Gets user consent for OmniStudio metadata tables cleanup
177+
*
178+
* @returns Promise<boolean> - true if user consents, false otherwise
179+
*/
180+
private async getMetadataCleanupConsent(): Promise<boolean> {
181+
const askWithTimeOut = PromptUtil.askWithTimeOut(this.messages);
182+
let validResponse = false;
183+
let consent = false;
184+
185+
while (!validResponse) {
186+
try {
187+
const resp = await askWithTimeOut(
188+
Logger.prompt.bind(Logger),
189+
this.messages.getMessage('metadataCleanupConsentMessage')
190+
);
191+
const response = typeof resp === 'string' ? resp.trim().toLowerCase() : '';
192+
193+
if (response === YES_SHORT || response === YES_LONG) {
194+
consent = true;
195+
validResponse = true;
196+
} else if (response === NO_SHORT || response === NO_LONG) {
197+
consent = false;
198+
validResponse = true;
199+
} else {
200+
Logger.error(this.messages.getMessage('invalidYesNoResponse'));
201+
}
202+
} catch (err) {
203+
Logger.error(this.messages.getMessage('requestTimedOut'));
204+
process.exit(1);
205+
}
206+
}
207+
return consent;
208+
}
151209
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { Connection, Messages } from '@salesforce/core';
2+
import { Logger } from '../logger';
3+
import { QueryTools } from '../query';
4+
import { NetUtils } from '../net';
5+
6+
/**
7+
* OmniStudioMetadataCleanupService
8+
*
9+
* This service checks for records in four OmniStudio metadata tables and cleans them if found:
10+
* - OmniUiCardConfig
11+
* - OmniScriptConfig
12+
* - OmniIntegrationProcConfig
13+
* - OmniDataTransformConfig
14+
*/
15+
16+
export class OmniStudioMetadataCleanupService {
17+
private static readonly CONFIG_TABLES = [
18+
'OmniUiCardConfig',
19+
'OmniScriptConfig',
20+
'OmniIntegrationProcConfig',
21+
'OmniDataTransformConfig',
22+
];
23+
24+
private readonly connection: Connection;
25+
private readonly messages: Messages;
26+
27+
public constructor(connection: Connection, messages: Messages) {
28+
this.messages = messages;
29+
this.connection = connection;
30+
}
31+
32+
/**
33+
* Checks if all config tables are clean (have no records)
34+
*
35+
* @returns Promise<boolean> - true if all tables are empty, false if any table has records
36+
*/
37+
public async hasCleanOmniStudioMetadataTables(): Promise<boolean> {
38+
try {
39+
for (const tableName of OmniStudioMetadataCleanupService.CONFIG_TABLES) {
40+
const recordIds = await QueryTools.queryIds(this.connection, tableName);
41+
if (recordIds.length > 0) {
42+
return false;
43+
}
44+
}
45+
return true;
46+
} catch (error) {
47+
Logger.error(this.messages.getMessage('errorCheckingMetadataTables', [String(error)]));
48+
return false;
49+
}
50+
}
51+
52+
/**
53+
* Checks all config tables for records and cleans them if found
54+
*
55+
* @returns Promise<boolean> - true if cleanup was successful, false otherwise
56+
*/
57+
public async cleanupOmniStudioMetadataTables(): Promise<boolean> {
58+
try {
59+
Logger.log(this.messages.getMessage('startingMetadataCleanup'));
60+
61+
let totalCleanedRecords = 0;
62+
const failedTables: string[] = [];
63+
64+
for (const tableName of OmniStudioMetadataCleanupService.CONFIG_TABLES) {
65+
const recordCount = await this.cleanupOmniStudioMetadataTable(tableName);
66+
67+
if (recordCount >= 0) {
68+
totalCleanedRecords += recordCount;
69+
} else {
70+
failedTables.push(tableName);
71+
}
72+
}
73+
74+
if (failedTables.length > 0) {
75+
Logger.error(this.messages.getMessage('failedToCleanTables', [failedTables.join(', ')]));
76+
return false;
77+
}
78+
79+
Logger.log(this.messages.getMessage('metadataCleanupCompleted', [totalCleanedRecords]));
80+
return true;
81+
} catch (error) {
82+
Logger.error(this.messages.getMessage('errorCheckingMetadataTables', [String(error)]));
83+
return false;
84+
}
85+
}
86+
87+
/**
88+
* Checks a specific table for records and cleans them if found
89+
*
90+
* @param tableName - Name of the table to check and clean
91+
* @returns Promise<number> - number of cleaned records, or -1 if failed
92+
*/
93+
private async cleanupOmniStudioMetadataTable(tableName: string): Promise<number> {
94+
const recordIds = await QueryTools.queryIds(this.connection, tableName);
95+
96+
if (recordIds.length === 0) {
97+
return 0;
98+
}
99+
100+
const deleteSuccess = await NetUtils.delete(this.connection, recordIds);
101+
return deleteSuccess ? recordIds.length : -1;
102+
}
103+
}

src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './query';
22
export * from './logging/debugtimer';
33
export * from './interfaces';
4+
export * from './config/OmniStudioMetadataCleanupService';

0 commit comments

Comments
 (0)