Skip to content

Commit

Permalink
[SQL Migration] Import Assessments (#24811)
Browse files Browse the repository at this point in the history
* [SQL Migration][New Migration Experience] Assessment Results Page Data Integration and Condition Handling (#24378)

* integration of assessment summary

* adding removed strings

* fixing import ui and conditions

* handling recommended configuration

* issue category added

* resolved comments

* reverting breaking changes

* fixing save and close while import

* update version

* fixed comment
  • Loading branch information
stuti149 authored Nov 15, 2023
1 parent b9526be commit 67d357a
Show file tree
Hide file tree
Showing 16 changed files with 565 additions and 66 deletions.
2 changes: 1 addition & 1 deletion extensions/sql-migration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "sql-migration",
"displayName": "%displayName%",
"description": "%description%",
"version": "1.5.0",
"version": "1.5.1",
"publisher": "Microsoft",
"preview": false,
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",
Expand Down
17 changes: 17 additions & 0 deletions extensions/sql-migration/src/api/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1331,3 +1331,20 @@ export async function clearDropDownWithLoading(dropDown: DropDownComponent): Pro
await dropDown.updateProperty('value', undefined);
await dropDown.updateProperty('values', []);
}

export async function promptUserForFile(filters: { [name: string]: string[] }): Promise<string> {
const options: vscode.OpenDialogOptions = {
defaultUri: vscode.Uri.file(getUserHome()!),
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
filters: filters,
};

const fileUris = await vscode.window.showOpenDialog(options);
if (fileUris && fileUris.length > 0 && fileUris[0]) {
return fileUris[0].fsPath;
}

return '';
}
4 changes: 4 additions & 0 deletions extensions/sql-migration/src/constants/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const providerId = 'SqlMigration';
export const extensionConfigSectionName = 'sqlMigration';
export const sqlConfigSectionName = 'sql';
export const configLogDebugInfo = 'logDebugInfo';
export const importAssessmentKey = "ImportAssessment";
export function serviceCrashMessage(error: string): string {
return localize('serviceCrashMessage', "Migration service component could not start. {0}", error);
}
Expand Down Expand Up @@ -227,6 +228,7 @@ export const ASSESSMENT_MIGRATION_WARNING_SQLDB = localize('sql.migration.assess
export const ASSESSMENT_MIGRATION_WARNING_SQLMI = localize('sql.migration.assessment.migration.warning.sqlmi', "Databases that are not ready for migration to Azure SQL Managed Instance can be migrated to SQL Server on Azure Virtual Machines. Alternatively, review assessment results for Azure SQL Database migration readiness.");
export const DATABASES_TABLE_TILE = localize('sql.migration.databases.table.title', "Databases");
export const SQL_SERVER_INSTANCE = localize('sql.migration.sql.server.instance', "SQL Server instance");
export const LOAD_ASSESSMENT_REPORT = localize('sql.migration.load.assessment.report', "Load assessment report");
export const SAVE_ASSESSMENT_REPORT = localize('sql.migration.save.assessment.report', "Save assessment report");
export const SAVE_RECOMMENDATION_REPORT = localize('sql.migration.save.recommendation.report', "Save recommendation report");
export function SAVE_ASSESSMENT_REPORT_SUCCESS(filePath: string): string {
Expand Down Expand Up @@ -1523,6 +1525,8 @@ export const MIGRATION_SERVICE_DESCRIPTION = localize('sql.migration.select.serv

// Desktop tabs
export const DESKTOP_MIGRATION_BUTTON_LABEL = localize('sql.migration.tab.button.migration.label', 'New migration');
export const DESKTOP_IMPORT_MIGRATION_BUTTON_LABEL = localize('sql.migration.tab.import.migration.label', 'Import assessment');
export const DESKTOP_IMPORT_MIGRATION_BUTTON_DESCRIPTION = localize('sql.migration.tab.import.migration.description', 'Import assessment to Azure SQL');
export const DESKTOP_MIGRATION_BUTTON_DESCRIPTION = localize('sql.migration.tab.button.migration.description', 'Migrate to Azure SQL');
export const DESKTOP_LOGIN_MIGRATION_BUTTON_LABEL = localize('sql.migration.tab.button.login.migration.label', 'New login migration (PREVIEW)');
export const DESKTOP_LOGIN_MIGRATION_BUTTON_DESCRIPTION = localize('sql.migration.tab.button.login.migration.description', 'Migrate logins to Azure SQL');
Expand Down
3 changes: 3 additions & 0 deletions extensions/sql-migration/src/dashboard/dashboardTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@ export class DashboardTab extends TabBase<DashboardTab> {
}

public async create(
context: vscode.ExtensionContext,
view: azdata.ModelView,
openMigrationsFcn: (status: AdsMigrationStatus) => Promise<void>,
serviceContextChangedEvent: vscode.EventEmitter<ServiceContextChangeEvent>,
statusBar: DashboardStatusBar): Promise<DashboardTab> {

this.context = context;
this.view = view;
this.openMigrationsFcn = openMigrationsFcn;
this.serviceContextChangedEvent = serviceContextChangedEvent;
Expand Down Expand Up @@ -143,6 +145,7 @@ export class DashboardTab extends TabBase<DashboardTab> {
toolbar.addToolbarItems([
<azdata.ToolbarComponent>{ component: this.createNewMigrationButton() },
<azdata.ToolbarComponent>{ component: this.createNewLoginMigrationButton() },
<azdata.ToolbarComponent>{ component: this.createImportMigrationButton() },
<azdata.ToolbarComponent>{ component: this.createNewHelpAndSupportButton() },
<azdata.ToolbarComponent>{ component: this.createFeedbackButton() },
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export class MigrationsListTab extends TabBase<MigrationsListTab> {
toolbar.addToolbarItems([
<azdata.ToolbarComponent>{ component: this.createNewMigrationButton(), toolbarSeparatorAfter: true },
<azdata.ToolbarComponent>{ component: this.createNewLoginMigrationButton(), toolbarSeparatorAfter: true },
<azdata.ToolbarComponent>{ component: this.createImportMigrationButton(), toolbarSeparatorAfter: true },
<azdata.ToolbarComponent>{ component: this.createNewHelpAndSupportButton() },
<azdata.ToolbarComponent>{ component: this.createFeedbackButton(), toolbarSeparatorAfter: true },
<azdata.ToolbarComponent>{ component: this._refreshLoader },
Expand Down
45 changes: 35 additions & 10 deletions extensions/sql-migration/src/dashboard/sqlServerDashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { MigrationCutoverDialogModel } from '../dialog/migrationCutover/migratio
import { RestartMigrationDialog } from '../dialog/restartMigration/restartMigrationDialog';
import { SqlMigrationServiceDetailsDialog } from '../dialog/sqlMigrationService/sqlMigrationServiceDetailsDialog';
import { MigrationLocalStorage } from '../models/migrationLocalStorage';
import { MigrationStateModel, SavedInfo } from '../models/stateMachine';
import { MigrationStateModel, Page, SavedInfo } from '../models/stateMachine';
import { logError, TelemetryViews } from '../telemetry';
import { WizardController } from '../wizard/wizardController';
import { DashboardStatusBar, ErrorEvent } from './DashboardStatusBar';
Expand All @@ -29,6 +29,7 @@ import { migrationServiceProvider } from '../service/provider';
import { ApiType, SqlMigrationService } from '../service/features';
import { getSourceConnectionId, getSourceConnectionProfile } from '../api/sqlUtils';
import { openRetryMigrationDialog } from '../dialog/retryMigration/retryMigrationDialog';
import { ImportAssessmentDialog } from '../dialog/assessment/importAssessmentDialog';

export interface MenuCommandArgs {
connectionId: string,
Expand Down Expand Up @@ -107,6 +108,7 @@ export class DashboardWidget {
};

const dashboardTab = await new DashboardTab().create(
this._context,
view,
async (filter: AdsMigrationStatus) => await openMigrationFcn(filter),
this._onServiceContextChanged,
Expand Down Expand Up @@ -533,20 +535,39 @@ export class DashboardWidget {
if (migrationService) {
this.stateModel = new MigrationStateModel(this._context, migrationService);
this._context.subscriptions.push(this.stateModel);

const wizardController = new WizardController(
this._context,
this.stateModel,
this._onServiceContextChanged);

const savedInfo = this.checkSavedInfo(serverName);
if (savedInfo) {
this.stateModel.savedInfo = savedInfo;
this.stateModel.serverName = serverName;
const savedAssessmentDialog = new SavedAssessmentDialog(
this._context,
this.stateModel,
this._onServiceContextChanged);
await savedAssessmentDialog.openDialog();

const importSavedInfo = this.checkSavedInfo(loc.importAssessmentKey);
if (importSavedInfo && importSavedInfo.closedPage === Page.ImportAssessment) {
await this.clearSavedInfo(loc.importAssessmentKey);
if (importSavedInfo.serverAssessment !== null) {
this.stateModel._assessmentResults = importSavedInfo.serverAssessment;
await this.stateModel.loadSavedInfo();

serverName = importSavedInfo.serverAssessment?.issues[0]?.serverName ??
importSavedInfo.serverAssessment?.databaseAssessments[0]?.issues[0]?.serverName;
this.stateModel.serverName = serverName;
}

const importAssessmentDialog = new ImportAssessmentDialog('ownerUri', this.stateModel, serverName);
await importAssessmentDialog.openDialog();
} else {
const savedAssessmentDialog = new SavedAssessmentDialog(
this._context,
this.stateModel,
this._onServiceContextChanged);
await savedAssessmentDialog.openDialog();
}
} else {
const wizardController = new WizardController(
this._context,
this.stateModel,
this._onServiceContextChanged);
await wizardController.openWizard();
}
}
Expand Down Expand Up @@ -582,6 +603,10 @@ export class DashboardWidget {
return this._context.globalState.get<SavedInfo>(`${this.stateModel.mementoString}.${serverName}`);
}

private async clearSavedInfo(serverName: string) {
await this._context.globalState.update(`${this.stateModel.mementoString}.${serverName}`, {});
}

public async launchNewSupportRequest(): Promise<void> {
await vscode.env.openExternal(vscode.Uri.parse(
`https://portal.azure.com/#blade/Microsoft_Azure_Support/HelpAndSupportBlade/newsupportrequest`));
Expand Down
41 changes: 41 additions & 0 deletions extensions/sql-migration/src/dashboard/tabBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import { getSelectedServiceStatus } from '../models/migrationLocalStorage';
import { MenuCommands, SqlMigrationExtensionId } from '../api/utils';
import { DashboardStatusBar } from './DashboardStatusBar';
import { ShowStatusMessageDialog } from '../dialog/generic/genericDialogs';
import * as utils from '../api/utils';
import * as fs from 'fs';
import { parseAssessmentReport } from '../dialog/assessment/assessmentUtils';
import { HelpAndSupportDialog } from '../dialog/help/helpAndSupportDialog';

export const EmptySettingValue = '-';
Expand Down Expand Up @@ -47,6 +50,8 @@ export abstract class TabBase<T> implements azdata.Tab, vscode.Disposable {
protected serviceContextChangedEvent!: vscode.EventEmitter<ServiceContextChangeEvent>;
protected statusBar!: DashboardStatusBar;

private mementoToken: string = 'sqlMigration.assessmentResults';

protected abstract initialize(view: azdata.ModelView): Promise<void>;

public abstract refresh(initialize?: boolean): Promise<void>;
Expand Down Expand Up @@ -137,6 +142,42 @@ export abstract class TabBase<T> implements azdata.Tab, vscode.Disposable {
return newMigrationButton;
}

protected createImportMigrationButton(): azdata.ButtonComponent {
const importMigrationButton = this.view.modelBuilder.button()
.withProps({
buttonType: azdata.ButtonType.Normal,
label: loc.DESKTOP_IMPORT_MIGRATION_BUTTON_LABEL,
description: loc.DESKTOP_IMPORT_MIGRATION_BUTTON_DESCRIPTION,
height: 24,
iconHeight: 24,
iconWidth: 24,
iconPath: IconPathHelper.addNew,
}).component();
this.disposables.push(
importMigrationButton.onDidClick(async () => {
const filepath = await utils.promptUserForFile({ 'Json (*.json)': ['json'] });
if (filepath) {
try {
const assessmentReportJson = fs.readFileSync(filepath, 'utf-8');
const assessmentReport = JSON.parse(assessmentReportJson);

const saveInfo = parseAssessmentReport(assessmentReport);
await this.context.globalState.update(`${this.mementoToken}.${loc.importAssessmentKey}`, saveInfo);
} catch (err) {
void vscode.window.showErrorMessage(err.message);
}

const actionId = MenuCommands.StartMigration;
const args = {
extensionId: SqlMigrationExtensionId,
issueTitle: loc.DASHBOARD_MIGRATE_TASK_BUTTON_TITLE,
};
await vscode.commands.executeCommand(actionId, args);
}
}));
return importMigrationButton;
}

protected createNewHelpAndSupportButton(): azdata.ButtonComponent {
const newHelpAndSupportButton = this.view.modelBuilder.button()
.withProps({
Expand Down
Loading

0 comments on commit 67d357a

Please sign in to comment.