add error banner for failed migration cutover and cancel migration (#17106)

This commit is contained in:
brian-harris
2021-09-21 23:31:36 -07:00
committed by GitHub
parent 4a715e473a
commit 155ea4c707
26 changed files with 250 additions and 224 deletions

View File

@@ -0,0 +1,13 @@
{
"parserOptions": {
"project": "./extensions/sql-migration/tsconfig.json"
},
"rules": {
"@typescript-eslint/no-floating-promises": [
"error",
{
"ignoreVoid": true
}
]
}
}

View File

@@ -547,7 +547,7 @@ export interface TargetLocation {
export interface BackupFileInfo { export interface BackupFileInfo {
fileName: string; fileName: string;
status: 'Arrived' | 'Uploading' | 'Uploaded' | 'Restoring' | 'Restored' | 'Cancelled' | 'Ignored'; status: 'Arrived' | 'Uploading' | 'Uploaded' | 'Restoring' | 'Restored' | 'Canceled' | 'Ignored';
totalSize: number; totalSize: number;
dataRead: number; dataRead: number;
dataWritten: number; dataWritten: number;

View File

@@ -230,6 +230,14 @@ export function get12HourTime(date: Date | undefined): string {
return (date ? date : new Date()).toLocaleTimeString([], localeTimeStringOptions); return (date ? date : new Date()).toLocaleTimeString([], localeTimeStringOptions);
} }
export function displayDialogErrorMessage(dialog: window.Dialog, text: string, error: Error): void {
dialog.message = {
level: window.MessageLevel.Error,
text: text,
description: error.message,
};
}
export function clearDialogMessage(dialog: window.Dialog): void { export function clearDialogMessage(dialog: window.Dialog): void {
dialog.message = { dialog.message = {
text: '' text: ''

View File

@@ -337,6 +337,7 @@ export const YES = localize('sql.migration.yes', "Yes");
export const NO = localize('sql.migration.no', "No"); export const NO = localize('sql.migration.no', "No");
export const EMPTY_TABLE_TEXT = localize('sql.migration.empty.table.text', "No backup files"); export const EMPTY_TABLE_TEXT = localize('sql.migration.empty.table.text', "No backup files");
export const EMPTY_TABLE_SUBTEXT = localize('sql.migration.empty.table.subtext', "If results were expected, verify the connection to the SQL Server instance."); export const EMPTY_TABLE_SUBTEXT = localize('sql.migration.empty.table.subtext', "If results were expected, verify the connection to the SQL Server instance.");
export const MIGRATION_CUTOVER_ERROR = localize('sql.migration.cutover.error', 'An error occurred while initiating cutover.');
//Migration confirm cutover dialog //Migration confirm cutover dialog
export const COMPLETING_CUTOVER_WARNING = localize('sql.migration.completing.cutover.warning', "Completing cutover without restoring all the backups may result in a data loss."); export const COMPLETING_CUTOVER_WARNING = localize('sql.migration.completing.cutover.warning', "Completing cutover without restoring all the backups may result in a data loss.");

View File

@@ -105,7 +105,7 @@ export class DashboardWidget {
})); }));
await view.initializeModel(container); await view.initializeModel(container);
this.refreshMigrations(); await this.refreshMigrations();
}); });
} }
@@ -267,7 +267,7 @@ export class DashboardWidget {
this._viewAllMigrationsButton.enabled = false; this._viewAllMigrationsButton.enabled = false;
this._migrationStatusCardLoadingContainer.loading = true; this._migrationStatusCardLoadingContainer.loading = true;
try { try {
this.setCurrentMigrations(await this.getMigrations()); await this.setCurrentMigrations(await this.getMigrations());
const migrations = await this.getCurrentMigrations(); const migrations = await this.getCurrentMigrations();
const inProgressMigrations = filterMigrations(migrations, AdsMigrationStatus.ONGOING); const inProgressMigrations = filterMigrations(migrations, AdsMigrationStatus.ONGOING);
let warningCount = 0; let warningCount = 0;
@@ -663,17 +663,17 @@ export class DashboardWidget {
let accounts = await azdata.accounts.getAllAccounts(); let accounts = await azdata.accounts.getAllAccounts();
if (accounts.length !== 0) { if (accounts.length !== 0) {
addAccountImage.updateCssStyles({ await addAccountImage.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
addAccountText.updateCssStyles({ await addAccountText.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
addAccountButton.updateCssStyles({ await addAccountButton.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
this._migrationStatusCardsContainer.updateCssStyles({ 'visibility': 'visible' }); await this._migrationStatusCardsContainer.updateCssStyles({ 'visibility': 'visible' });
this._viewAllMigrationsButton.updateCssStyles({ 'visibility': 'visible' }); await this._viewAllMigrationsButton.updateCssStyles({ 'visibility': 'visible' });
} }
await this.refreshMigrations(); await this.refreshMigrations();
})); }));
@@ -692,17 +692,17 @@ export class DashboardWidget {
let accounts = await azdata.accounts.getAllAccounts(); let accounts = await azdata.accounts.getAllAccounts();
if (accounts.length === 0) { if (accounts.length === 0) {
addAccountImage.updateCssStyles({ await addAccountImage.updateCssStyles({
'display': 'block' 'display': 'block'
}); });
addAccountText.updateCssStyles({ await addAccountText.updateCssStyles({
'display': 'block' 'display': 'block'
}); });
addAccountButton.updateCssStyles({ await addAccountButton.updateCssStyles({
'display': 'block' 'display': 'block'
}); });
this._migrationStatusCardsContainer.updateCssStyles({ 'visibility': 'hidden' }); await this._migrationStatusCardsContainer.updateCssStyles({ 'visibility': 'hidden' });
this._viewAllMigrationsButton.updateCssStyles({ 'visibility': 'hidden' }); await this._viewAllMigrationsButton.updateCssStyles({ 'visibility': 'hidden' });
} }
this._inProgressMigrationButton = this.createStatusCard( this._inProgressMigrationButton = this.createStatusCard(
@@ -774,7 +774,7 @@ export class DashboardWidget {
loc.MIGRATION_NOT_STARTED loc.MIGRATION_NOT_STARTED
); );
this._disposables.push(this._notStartedMigrationCard.container.onDidClick((e) => { this._disposables.push(this._notStartedMigrationCard.container.onDidClick((e) => {
vscode.window.showInformationMessage('Feature coming soon'); void vscode.window.showInformationMessage('Feature coming soon');
})); }));
this._migrationStatusCardLoadingContainer = view.modelBuilder.loadingComponent().withItem(this._migrationStatusCardsContainer).component(); this._migrationStatusCardLoadingContainer = view.modelBuilder.loadingComponent().withItem(this._migrationStatusCardsContainer).component();

View File

@@ -89,7 +89,7 @@ export class AssessmentResultsDialog {
} else { } else {
this._model._miDbs = this._tree.selectedDbs(); this._model._miDbs = this._tree.selectedDbs();
} }
this._skuRecommendationPage.refreshCardText(); await this._skuRecommendationPage.refreshCardText();
this.model.refreshDatabaseBackupPage = true; this.model.refreshDatabaseBackupPage = true;
this._isOpen = false; this._isOpen = false;
} }

View File

@@ -183,8 +183,8 @@ export class SqlDatabaseTree {
} }
).component(); ).component();
this._disposables.push(this._databaseTable.onDataChanged(() => { this._disposables.push(this._databaseTable.onDataChanged(async () => {
this._databaseCount.updateProperties({ await this._databaseCount.updateProperties({
'value': constants.DATABASES(this.selectedDbs().length, this._model._databaseAssessment.length) 'value': constants.DATABASES(this.selectedDbs().length, this._model._databaseAssessment.length)
}); });
})); }));
@@ -198,10 +198,10 @@ export class SqlDatabaseTree {
this._dbName.value = this._dbNames[e.row]; this._dbName.value = this._dbNames[e.row];
this._recommendationTitle.value = constants.ISSUES_COUNT(this._activeIssues.length); this._recommendationTitle.value = constants.ISSUES_COUNT(this._activeIssues.length);
this._recommendation.value = constants.ISSUES_DETAILS; this._recommendation.value = constants.ISSUES_DETAILS;
this._resultComponent.updateCssStyles({ await this._resultComponent.updateCssStyles({
'display': 'block' 'display': 'block'
}); });
this._dbMessageContainer.updateCssStyles({ await this._dbMessageContainer.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
await this.refreshResults(); await this.refreshResults();
@@ -296,10 +296,10 @@ export class SqlDatabaseTree {
this._disposables.push(this._instanceTable.onRowSelected(async (e) => { this._disposables.push(this._instanceTable.onRowSelected(async (e) => {
this._activeIssues = this._model._assessmentResults?.issues; this._activeIssues = this._model._assessmentResults?.issues;
this._dbName.value = this._serverName; this._dbName.value = this._serverName;
this._resultComponent.updateCssStyles({ await this._resultComponent.updateCssStyles({
'display': 'block' 'display': 'block'
}); });
this._dbMessageContainer.updateCssStyles({ await this._dbMessageContainer.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
this._recommendation.value = constants.WARNINGS_DETAILS; this._recommendation.value = constants.WARNINGS_DETAILS;
@@ -778,37 +778,37 @@ export class SqlDatabaseTree {
if (this._targetType === MigrationTargetType.SQLMI) { if (this._targetType === MigrationTargetType.SQLMI) {
if (this._activeIssues.length === 0) { if (this._activeIssues.length === 0) {
/// show no issues here /// show no issues here
this._assessmentsTable.updateCssStyles({ await this._assessmentsTable.updateCssStyles({
'display': 'none', 'display': 'none',
'border-right': 'none' 'border-right': 'none'
}); });
this._assessmentContainer.updateCssStyles({ await this._assessmentContainer.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
this._noIssuesContainer.updateCssStyles({ await this._noIssuesContainer.updateCssStyles({
'display': 'flex' 'display': 'flex'
}); });
} else { } else {
this._assessmentContainer.updateCssStyles({ await this._assessmentContainer.updateCssStyles({
'display': 'flex' 'display': 'flex'
}); });
this._assessmentsTable.updateCssStyles({ await this._assessmentsTable.updateCssStyles({
'display': 'flex', 'display': 'flex',
'border-right': 'solid 1px' 'border-right': 'solid 1px'
}); });
this._noIssuesContainer.updateCssStyles({ await this._noIssuesContainer.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
} }
} else { } else {
this._assessmentsTable.updateCssStyles({ await this._assessmentsTable.updateCssStyles({
'display': 'none', 'display': 'none',
'border-right': 'none' 'border-right': 'none'
}); });
this._assessmentContainer.updateCssStyles({ await this._assessmentContainer.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
this._noIssuesContainer.updateCssStyles({ await this._noIssuesContainer.updateCssStyles({
'display': 'flex' 'display': 'flex'
}); });
this._recommendationTitle.value = constants.ASSESSMENT_RESULTS; this._recommendationTitle.value = constants.ASSESSMENT_RESULTS;

View File

@@ -65,8 +65,8 @@ export class CreateResourceGroupDialog {
return valid; return valid;
}).component(); }).component();
this._disposables.push(resourceGroupName.onTextChanged(e => { this._disposables.push(resourceGroupName.onTextChanged(async e => {
errorBox.updateCssStyles({ await errorBox.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
})); }));
@@ -78,7 +78,7 @@ export class CreateResourceGroupDialog {
}).component(); }).component();
this._disposables.push(okButton.onDidClick(async e => { this._disposables.push(okButton.onDidClick(async e => {
errorBox.updateCssStyles({ await errorBox.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
okButton.enabled = false; okButton.enabled = false;
@@ -88,12 +88,12 @@ export class CreateResourceGroupDialog {
const resourceGroup = await createResourceGroup(this._azureAccount, this._subscription, resourceGroupName.value!, this._location); const resourceGroup = await createResourceGroup(this._azureAccount, this._subscription, resourceGroupName.value!, this._location);
this._creationEvent.emit('done', resourceGroup); this._creationEvent.emit('done', resourceGroup);
} catch (e) { } catch (e) {
errorBox.updateCssStyles({ await errorBox.updateCssStyles({
'display': 'inline' 'display': 'inline'
}); });
errorBox.text = e.toString(); errorBox.text = e.toString();
cancelButton.enabled = true; cancelButton.enabled = true;
resourceGroupName.validate(); await resourceGroupName.validate();
} finally { } finally {
loading.loading = false; loading.loading = false;
} }
@@ -182,8 +182,8 @@ export class CreateResourceGroupDialog {
d => { try { d.dispose(); } catch { } }); d => { try { d.dispose(); } catch { } });
})); }));
return view.initializeModel(form).then(v => { return view.initializeModel(form).then(async v => {
resourceGroupName.focus(); await resourceGroupName.focus();
}); });
}); });
this._dialogObject.okButton.label = constants.APPLY; this._dialogObject.okButton.label = constants.APPLY;

View File

@@ -158,8 +158,8 @@ export class CreateSqlMigrationServiceDialog {
d => { try { d.dispose(); } catch { } }); d => { try { d.dispose(); } catch { } });
})); }));
return view.initializeModel(form).then(() => { return view.initializeModel(form).then(async () => {
this.populateSubscriptions(); await this.populateSubscriptions();
}); });
}); });
@@ -167,15 +167,15 @@ export class CreateSqlMigrationServiceDialog {
this._testConnectionButton.hidden = true; this._testConnectionButton.hidden = true;
this._disposables.push(this._testConnectionButton.onClick(async (e) => { this._disposables.push(this._testConnectionButton.onClick(async (e) => {
this._refreshLoadingComponent.loading = true; this._refreshLoadingComponent.loading = true;
this._connectionStatus.updateCssStyles({ await this._connectionStatus.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
try { try {
await this.refreshStatus(); await this.refreshStatus();
} catch (e) { } catch (e) {
vscode.window.showErrorMessage(e); void vscode.window.showErrorMessage(e);
} }
this._connectionStatus.updateCssStyles({ await this._connectionStatus.updateCssStyles({
'display': 'inline' 'display': 'inline'
}); });
this._refreshLoadingComponent.loading = false; this._refreshLoadingComponent.loading = false;
@@ -275,7 +275,7 @@ export class CreateSqlMigrationServiceDialog {
name: createdResourceGroup.name name: createdResourceGroup.name
}; };
this.migrationServiceResourceGroupDropdown.loading = false; this.migrationServiceResourceGroupDropdown.loading = false;
this.migrationServiceResourceGroupDropdown.focus(); await this.migrationServiceResourceGroupDropdown.focus();
} }
})); }));
@@ -547,7 +547,7 @@ export class CreateSqlMigrationServiceDialog {
const state = migrationServiceStatus.properties.integrationRuntimeState; const state = migrationServiceStatus.properties.integrationRuntimeState;
if (state === 'Online') { if (state === 'Online') {
this._connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{ await this._connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
text: constants.SERVICE_READY(this._createdMigrationService!.name, this.irNodes.join(', ')), text: constants.SERVICE_READY(this._createdMigrationService!.name, this.irNodes.join(', ')),
style: 'success', style: 'success',
CSSStyles: { CSSStyles: {
@@ -557,7 +557,7 @@ export class CreateSqlMigrationServiceDialog {
this._dialogObject.okButton.enabled = true; this._dialogObject.okButton.enabled = true;
} else { } else {
this._connectionStatus.text = constants.SERVICE_NOT_READY(this._createdMigrationService!.name); this._connectionStatus.text = constants.SERVICE_NOT_READY(this._createdMigrationService!.name);
this._connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{ await this._connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
text: constants.SERVICE_NOT_READY(this._createdMigrationService!.name), text: constants.SERVICE_NOT_READY(this._createdMigrationService!.name),
style: 'warning', style: 'warning',
CSSStyles: { CSSStyles: {
@@ -581,9 +581,9 @@ export class CreateSqlMigrationServiceDialog {
ariaLabel: constants.COPY_KEY1, ariaLabel: constants.COPY_KEY1,
}).component(); }).component();
this._disposables.push(this._copyKey1Button.onDidClick((e) => { this._disposables.push(this._copyKey1Button.onDidClick(async (e) => {
vscode.env.clipboard.writeText(<string>this.migrationServiceAuthKeyTable.dataValues![0][1].value); await vscode.env.clipboard.writeText(<string>this.migrationServiceAuthKeyTable.dataValues![0][1].value);
vscode.window.showInformationMessage(constants.SERVICE_KEY1_COPIED_HELP); void vscode.window.showInformationMessage(constants.SERVICE_KEY1_COPIED_HELP);
})); }));
this._copyKey2Button = this._view.modelBuilder.button().withProps({ this._copyKey2Button = this._view.modelBuilder.button().withProps({
@@ -592,9 +592,9 @@ export class CreateSqlMigrationServiceDialog {
ariaLabel: constants.COPY_KEY2, ariaLabel: constants.COPY_KEY2,
}).component(); }).component();
this._disposables.push(this._copyKey2Button.onDidClick((e) => { this._disposables.push(this._copyKey2Button.onDidClick(async (e) => {
vscode.env.clipboard.writeText(<string>this.migrationServiceAuthKeyTable.dataValues![1][1].value); await vscode.env.clipboard.writeText(<string>this.migrationServiceAuthKeyTable.dataValues![1][1].value);
vscode.window.showInformationMessage(constants.SERVICE_KEY2_COPIED_HELP); void vscode.window.showInformationMessage(constants.SERVICE_KEY2_COPIED_HELP);
})); }));
this._refreshKey1Button = this._view.modelBuilder.button().withProps({ this._refreshKey1Button = this._view.modelBuilder.button().withProps({
@@ -617,7 +617,7 @@ export class CreateSqlMigrationServiceDialog {
//TODO: add refresh logic //TODO: add refresh logic
})); }));
this.migrationServiceAuthKeyTable.updateProperties({ await this.migrationServiceAuthKeyTable.updateProperties({
dataValues: [ dataValues: [
[ [
{ {

View File

@@ -115,9 +115,9 @@ export class ConfirmCutoverDialog {
this._dialogObject.okButton.enabled = false; this._dialogObject.okButton.enabled = false;
this._dialogObject.okButton.label = constants.COMPLETE_CUTOVER; this._dialogObject.okButton.label = constants.COMPLETE_CUTOVER;
this._disposables.push(this._dialogObject.okButton.onClick((e) => { this._disposables.push(this._dialogObject.okButton.onClick(async (e) => {
this.migrationCutoverModel.startCutover(); await this.migrationCutoverModel.startCutover();
vscode.window.showInformationMessage(constants.CUTOVER_IN_PROGRESS(this.migrationCutoverModel._migration.migrationContext.properties.sourceDatabaseName)); void vscode.window.showInformationMessage(constants.CUTOVER_IN_PROGRESS(this.migrationCutoverModel._migration.migrationContext.properties.sourceDatabaseName));
})); }));
const formBuilder = view.modelBuilder.formContainer().withFormItems( const formBuilder = view.modelBuilder.formContainer().withFormItems(
@@ -235,14 +235,14 @@ export class ConfirmCutoverDialog {
if (expanded) { if (expanded) {
containerHeading.iconPath = IconPathHelper.expandButtonClosed; containerHeading.iconPath = IconPathHelper.expandButtonClosed;
containerHeading.iconHeight = 12; containerHeading.iconHeight = 12;
fileTable.updateCssStyles({ await fileTable.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
} else { } else {
containerHeading.iconPath = IconPathHelper.expandButtonOpen; containerHeading.iconPath = IconPathHelper.expandButtonOpen;
containerHeading.iconHeight = 8; containerHeading.iconHeight = 8;
fileTable.updateCssStyles({ await fileTable.updateCssStyles({
'display': 'inline' 'display': 'inline'
}); });
} }

View File

@@ -6,10 +6,10 @@
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { IconPathHelper } from '../../constants/iconPathHelper'; import { IconPathHelper } from '../../constants/iconPathHelper';
import { MigrationContext, MigrationStatus } from '../../models/migrationLocalStorage'; import { BackupFileInfoStatus, MigrationContext, MigrationStatus } from '../../models/migrationLocalStorage';
import { MigrationCutoverDialogModel } from './migrationCutoverDialogModel'; import { MigrationCutoverDialogModel } from './migrationCutoverDialogModel';
import * as loc from '../../constants/strings'; import * as loc from '../../constants/strings';
import { convertByteSizeToReadableUnit, convertIsoTimeToLocalTime, getSqlServerName, getMigrationStatusImage, SupportedAutoRefreshIntervals, clearDialogMessage } from '../../api/utils'; import { convertByteSizeToReadableUnit, convertIsoTimeToLocalTime, getSqlServerName, getMigrationStatusImage, SupportedAutoRefreshIntervals, clearDialogMessage, displayDialogErrorMessage } from '../../api/utils';
import { EOL } from 'os'; import { EOL } from 'os';
import { ConfirmCutoverDialog } from './confirmCutoverDialog'; import { ConfirmCutoverDialog } from './confirmCutoverDialog';
@@ -201,7 +201,7 @@ export class MigrationCutoverDialog {
let formItems = [ let formItems = [
{ component: this.migrationContainerHeader() }, { component: this.migrationContainerHeader() },
{ component: this._view.modelBuilder.separator().withProps({ width: 1000 }).component() }, { component: this._view.modelBuilder.separator().withProps({ width: 1000 }).component() },
{ component: this.migrationInfoGrid() }, { component: await this.migrationInfoGrid() },
{ component: this._view.modelBuilder.separator().withProps({ width: 1000 }).component() }, { component: this._view.modelBuilder.separator().withProps({ width: 1000 }).component() },
{ component: this._fileCount }, { component: this._fileCount },
{ component: this._fileTable }, { component: this._fileTable },
@@ -316,6 +316,10 @@ export class MigrationCutoverDialog {
const dialog = new ConfirmCutoverDialog(this._model); const dialog = new ConfirmCutoverDialog(this._model);
await dialog.initialize(); await dialog.initialize();
await this.refreshStatus(); await this.refreshStatus();
if (this._model.CutoverError) {
displayDialogErrorMessage(this._dialogObject, loc.MIGRATION_CUTOVER_ERROR, this._model.CutoverError);
}
})); }));
headerActions.addItem(this._cutoverButton, { headerActions.addItem(this._cutoverButton, {
@@ -336,10 +340,13 @@ export class MigrationCutoverDialog {
}).component(); }).component();
this._disposables.push(this._cancelButton.onDidClick((e) => { this._disposables.push(this._cancelButton.onDidClick((e) => {
vscode.window.showInformationMessage(loc.CANCEL_MIGRATION_CONFIRMATION, { modal: true }, loc.YES, loc.NO).then(async (v) => { void vscode.window.showInformationMessage(loc.CANCEL_MIGRATION_CONFIRMATION, { modal: true }, loc.YES, loc.NO).then(async (v) => {
if (v === loc.YES) { if (v === loc.YES) {
await this._model.cancelMigration(); await this._model.cancelMigration();
await this.refreshStatus(); await this.refreshStatus();
if (this._model.CancelMigrationError) {
displayDialogErrorMessage(this._dialogObject, loc.MIGRATION_CANCELLATION_ERROR, this._model.CancelMigrationError);
}
} }
}); });
})); }));
@@ -382,9 +389,9 @@ export class MigrationCutoverDialog {
this._disposables.push(this._copyDatabaseMigrationDetails.onDidClick(async (e) => { this._disposables.push(this._copyDatabaseMigrationDetails.onDidClick(async (e) => {
await this.refreshStatus(); await this.refreshStatus();
vscode.env.clipboard.writeText(this.getMigrationDetails()); await vscode.env.clipboard.writeText(this.getMigrationDetails());
vscode.window.showInformationMessage(loc.DETAILS_COPIED); void vscode.window.showInformationMessage(loc.DETAILS_COPIED);
})); }));
headerActions.addItem(this._copyDatabaseMigrationDetails, { headerActions.addItem(this._copyDatabaseMigrationDetails, {
@@ -451,7 +458,7 @@ export class MigrationCutoverDialog {
return header; return header;
} }
private migrationInfoGrid(): azdata.FlexContainer { private async migrationInfoGrid(): Promise<azdata.FlexContainer> {
const addInfoFieldToContainer = (infoField: InfoFieldSchema, container: azdata.FlexContainer): void => { const addInfoFieldToContainer = (infoField: InfoFieldSchema, container: azdata.FlexContainer): void => {
container.addItem(infoField.flexContainer, { container.addItem(infoField.flexContainer, {
CSSStyles: { CSSStyles: {
@@ -463,9 +470,9 @@ export class MigrationCutoverDialog {
const flexServer = this._view.modelBuilder.flexContainer().withLayout({ const flexServer = this._view.modelBuilder.flexContainer().withLayout({
flexFlow: 'column' flexFlow: 'column'
}).component(); }).component();
this._sourceDatabaseInfoField = this.createInfoField(loc.SOURCE_DATABASE, ''); this._sourceDatabaseInfoField = await this.createInfoField(loc.SOURCE_DATABASE, '');
this._sourceDetailsInfoField = this.createInfoField(loc.SOURCE_SERVER, ''); this._sourceDetailsInfoField = await this.createInfoField(loc.SOURCE_SERVER, '');
this._sourceVersionInfoField = this.createInfoField(loc.SOURCE_VERSION, ''); this._sourceVersionInfoField = await this.createInfoField(loc.SOURCE_VERSION, '');
addInfoFieldToContainer(this._sourceDatabaseInfoField, flexServer); addInfoFieldToContainer(this._sourceDatabaseInfoField, flexServer);
addInfoFieldToContainer(this._sourceDetailsInfoField, flexServer); addInfoFieldToContainer(this._sourceDetailsInfoField, flexServer);
addInfoFieldToContainer(this._sourceVersionInfoField, flexServer); addInfoFieldToContainer(this._sourceVersionInfoField, flexServer);
@@ -473,9 +480,9 @@ export class MigrationCutoverDialog {
const flexTarget = this._view.modelBuilder.flexContainer().withLayout({ const flexTarget = this._view.modelBuilder.flexContainer().withLayout({
flexFlow: 'column' flexFlow: 'column'
}).component(); }).component();
this._targetDatabaseInfoField = this.createInfoField(loc.TARGET_DATABASE_NAME, ''); this._targetDatabaseInfoField = await this.createInfoField(loc.TARGET_DATABASE_NAME, '');
this._targetServerInfoField = this.createInfoField(loc.TARGET_SERVER, ''); this._targetServerInfoField = await this.createInfoField(loc.TARGET_SERVER, '');
this._targetVersionInfoField = this.createInfoField(loc.TARGET_VERSION, ''); this._targetVersionInfoField = await this.createInfoField(loc.TARGET_VERSION, '');
addInfoFieldToContainer(this._targetDatabaseInfoField, flexTarget); addInfoFieldToContainer(this._targetDatabaseInfoField, flexTarget);
addInfoFieldToContainer(this._targetServerInfoField, flexTarget); addInfoFieldToContainer(this._targetServerInfoField, flexTarget);
addInfoFieldToContainer(this._targetVersionInfoField, flexTarget); addInfoFieldToContainer(this._targetVersionInfoField, flexTarget);
@@ -484,9 +491,9 @@ export class MigrationCutoverDialog {
const flexStatus = this._view.modelBuilder.flexContainer().withLayout({ const flexStatus = this._view.modelBuilder.flexContainer().withLayout({
flexFlow: 'column' flexFlow: 'column'
}).component(); }).component();
this._migrationStatusInfoField = this.createInfoField(loc.MIGRATION_STATUS, '', false, ' '); this._migrationStatusInfoField = await this.createInfoField(loc.MIGRATION_STATUS, '', false, ' ');
this._fullBackupFileOnInfoField = this.createInfoField(loc.FULL_BACKUP_FILES, '', isBlobMigration); this._fullBackupFileOnInfoField = await this.createInfoField(loc.FULL_BACKUP_FILES, '', isBlobMigration);
this._backupLocationInfoField = this.createInfoField(loc.BACKUP_LOCATION, ''); this._backupLocationInfoField = await this.createInfoField(loc.BACKUP_LOCATION, '');
addInfoFieldToContainer(this._migrationStatusInfoField, flexStatus); addInfoFieldToContainer(this._migrationStatusInfoField, flexStatus);
addInfoFieldToContainer(this._fullBackupFileOnInfoField, flexStatus); addInfoFieldToContainer(this._fullBackupFileOnInfoField, flexStatus);
addInfoFieldToContainer(this._backupLocationInfoField, flexStatus); addInfoFieldToContainer(this._backupLocationInfoField, flexStatus);
@@ -494,9 +501,9 @@ export class MigrationCutoverDialog {
const flexFile = this._view.modelBuilder.flexContainer().withLayout({ const flexFile = this._view.modelBuilder.flexContainer().withLayout({
flexFlow: 'column' flexFlow: 'column'
}).component(); }).component();
this._lastLSNInfoField = this.createInfoField(loc.LAST_APPLIED_LSN, '', isBlobMigration); this._lastLSNInfoField = await this.createInfoField(loc.LAST_APPLIED_LSN, '', isBlobMigration);
this._lastAppliedBackupInfoField = this.createInfoField(loc.LAST_APPLIED_BACKUP_FILES, ''); this._lastAppliedBackupInfoField = await this.createInfoField(loc.LAST_APPLIED_BACKUP_FILES, '');
this._lastAppliedBackupTakenOnInfoField = this.createInfoField(loc.LAST_APPLIED_BACKUP_FILES_TAKEN_ON, '', isBlobMigration); this._lastAppliedBackupTakenOnInfoField = await this.createInfoField(loc.LAST_APPLIED_BACKUP_FILES_TAKEN_ON, '', isBlobMigration);
addInfoFieldToContainer(this._lastLSNInfoField, flexFile); addInfoFieldToContainer(this._lastLSNInfoField, flexFile);
addInfoFieldToContainer(this._lastAppliedBackupInfoField, flexFile); addInfoFieldToContainer(this._lastAppliedBackupInfoField, flexFile);
addInfoFieldToContainer(this._lastAppliedBackupTakenOnInfoField, flexFile); addInfoFieldToContainer(this._lastAppliedBackupTakenOnInfoField, flexFile);
@@ -558,7 +565,7 @@ export class MigrationCutoverDialog {
clearDialogMessage(this._dialogObject); clearDialogMessage(this._dialogObject);
if (this._isOnlineMigration()) { if (this._isOnlineMigration()) {
this._cutoverButton.updateCssStyles({ await this._cutoverButton.updateCssStyles({
'display': 'inline' 'display': 'inline'
}); });
} }
@@ -660,22 +667,22 @@ export class MigrationCutoverDialog {
this._lastAppliedBackupTakenOnInfoField.text.value = lastAppliedBackupFileTakenOn! ? convertIsoTimeToLocalTime(lastAppliedBackupFileTakenOn).toLocaleString() : '-'; this._lastAppliedBackupTakenOnInfoField.text.value = lastAppliedBackupFileTakenOn! ? convertIsoTimeToLocalTime(lastAppliedBackupFileTakenOn).toLocaleString() : '-';
if (this._shouldDisplayBackupFileTable()) { if (this._shouldDisplayBackupFileTable()) {
this._fileCount.updateCssStyles({ await this._fileCount.updateCssStyles({
display: 'inline' display: 'inline'
}); });
this._fileTable.updateCssStyles({ await this._fileTable.updateCssStyles({
display: 'inline' display: 'inline'
}); });
this._fileCount.value = loc.ACTIVE_BACKUP_FILES_ITEMS(tableData.length); this._fileCount.value = loc.ACTIVE_BACKUP_FILES_ITEMS(tableData.length);
if (tableData.length === 0) { if (tableData.length === 0) {
this._emptyTableFill.updateCssStyles({ await this._emptyTableFill.updateCssStyles({
'display': 'flex' 'display': 'flex'
}); });
this._fileTable.height = '50px'; this._fileTable.height = '50px';
} else { } else {
this._emptyTableFill.updateCssStyles({ await this._emptyTableFill.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
this._fileTable.height = '300px'; this._fileTable.height = '300px';
@@ -698,25 +705,21 @@ export class MigrationCutoverDialog {
} }
} }
this._cutoverButton.enabled = false;
if (migrationStatusTextValue === MigrationStatus.InProgress) { if (migrationStatusTextValue === MigrationStatus.InProgress) {
const restoredCount = (this._model.migrationStatus.properties.migrationStatusDetails?.activeBackupSets?.filter(a => a.listOfBackupFiles[0].status === 'Restored'))?.length ?? 0; const restoredCount = this._model.migrationStatus.properties.migrationStatusDetails?.activeBackupSets?.filter(
(a) => a.listOfBackupFiles[0].status === BackupFileInfoStatus.Restored)?.length ?? 0;
if (restoredCount > 0 || isBlobMigration) { if (restoredCount > 0 || isBlobMigration) {
this._cutoverButton.enabled = true; this._cutoverButton.enabled = true;
} }
} else {
this._cutoverButton.enabled = false;
} }
this._cancelButton.enabled = this._cancelButton.enabled =
migrationStatusTextValue === MigrationStatus.Creating || migrationStatusTextValue === MigrationStatus.Creating ||
migrationStatusTextValue === MigrationStatus.InProgress; migrationStatusTextValue === MigrationStatus.InProgress;
} catch (e) { } catch (e) {
this._dialogObject.message = { displayDialogErrorMessage(this._dialogObject, loc.MIGRATION_STATUS_REFRESH_ERROR, e);
level: azdata.window.MessageLevel.Error,
text: loc.MIGRATION_STATUS_REFRESH_ERROR,
description: e.message
};
console.log(e); console.log(e);
} finally { } finally {
this.isRefreshing = false; this.isRefreshing = false;
@@ -724,17 +727,17 @@ export class MigrationCutoverDialog {
} }
} }
private createInfoField(label: string, value: string, defaultHidden: boolean = false, iconPath?: azdata.IconPath): { private async createInfoField(label: string, value: string, defaultHidden: boolean = false, iconPath?: azdata.IconPath): Promise<{
flexContainer: azdata.FlexContainer, flexContainer: azdata.FlexContainer,
text: azdata.TextComponent, text: azdata.TextComponent,
icon?: azdata.ImageComponent icon?: azdata.ImageComponent
} { }> {
const flexContainer = this._view.modelBuilder.flexContainer().withLayout({ const flexContainer = this._view.modelBuilder.flexContainer().withLayout({
flexFlow: 'column' flexFlow: 'column'
}).component(); }).component();
if (defaultHidden) { if (defaultHidden) {
flexContainer.updateCssStyles({ await flexContainer.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
} }

View File

@@ -4,12 +4,14 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { getMigrationStatus, DatabaseMigration, startMigrationCutover, stopMigration, getMigrationAsyncOperationDetails, AzureAsyncOperationResource, BackupFileInfo, getResourceGroupFromId } from '../../api/azure'; import { getMigrationStatus, DatabaseMigration, startMigrationCutover, stopMigration, getMigrationAsyncOperationDetails, AzureAsyncOperationResource, BackupFileInfo, getResourceGroupFromId } from '../../api/azure';
import { MigrationContext } from '../../models/migrationLocalStorage'; import { BackupFileInfoStatus, MigrationContext } from '../../models/migrationLocalStorage';
import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../../telemtery'; import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../../telemtery';
import * as constants from '../../constants/strings'; import * as constants from '../../constants/strings';
import { getMigrationTargetType, getMigrationMode } from '../../constants/helper'; import { getMigrationTargetType, getMigrationMode } from '../../constants/helper';
export class MigrationCutoverDialogModel { export class MigrationCutoverDialogModel {
public CutoverError?: Error;
public CancelMigrationError?: Error;
public migrationStatus!: DatabaseMigration; public migrationStatus!: DatabaseMigration;
public migrationOpStatus!: AzureAsyncOperationResource; public migrationOpStatus!: AzureAsyncOperationResource;
@@ -47,6 +49,7 @@ export class MigrationCutoverDialogModel {
public async startCutover(): Promise<DatabaseMigration | undefined> { public async startCutover(): Promise<DatabaseMigration | undefined> {
try { try {
this.CutoverError = undefined;
if (this.migrationStatus) { if (this.migrationStatus) {
const cutover = await startMigrationCutover( const cutover = await startMigrationCutover(
this._migration.azureAccount, this._migration.azureAccount,
@@ -66,6 +69,7 @@ export class MigrationCutoverDialogModel {
return cutover; return cutover;
} }
} catch (error) { } catch (error) {
this.CutoverError = error;
console.log(error); console.log(error);
} }
return undefined!; return undefined!;
@@ -73,6 +77,7 @@ export class MigrationCutoverDialogModel {
public async cancelMigration(): Promise<void> { public async cancelMigration(): Promise<void> {
try { try {
this.CancelMigrationError = undefined;
if (this.migrationStatus) { if (this.migrationStatus) {
const cutoverStartTime = new Date().toString(); const cutoverStartTime = new Date().toString();
await stopMigration( await stopMigration(
@@ -93,6 +98,7 @@ export class MigrationCutoverDialogModel {
); );
} }
} catch (error) { } catch (error) {
this.CancelMigrationError = error;
console.log(error); console.log(error);
} }
return undefined!; return undefined!;
@@ -126,7 +132,7 @@ export class MigrationCutoverDialogModel {
const files: BackupFileInfo[] = []; const files: BackupFileInfo[] = [];
this.migrationStatus.properties.migrationStatusDetails?.activeBackupSets?.forEach(abs => { this.migrationStatus.properties.migrationStatusDetails?.activeBackupSets?.forEach(abs => {
abs.listOfBackupFiles.forEach(f => { abs.listOfBackupFiles.forEach(f => {
if (f.status !== 'Restored') { if (f.status !== BackupFileInfoStatus.Restored) {
files.push(f); files.push(f);
} }
}); });

View File

@@ -10,7 +10,7 @@ import { MigrationContext, MigrationLocalStorage, MigrationStatus } from '../../
import { MigrationCutoverDialog } from '../migrationCutover/migrationCutoverDialog'; import { MigrationCutoverDialog } from '../migrationCutover/migrationCutoverDialog';
import { AdsMigrationStatus, MigrationStatusDialogModel } from './migrationStatusDialogModel'; import { AdsMigrationStatus, MigrationStatusDialogModel } from './migrationStatusDialogModel';
import * as loc from '../../constants/strings'; import * as loc from '../../constants/strings';
import { clearDialogMessage, convertTimeDifferenceToDuration, filterMigrations, getMigrationStatusImage, SupportedAutoRefreshIntervals } from '../../api/utils'; import { clearDialogMessage, convertTimeDifferenceToDuration, displayDialogErrorMessage, filterMigrations, getMigrationStatusImage, SupportedAutoRefreshIntervals } from '../../api/utils';
import { SqlMigrationServiceDetailsDialog } from '../sqlMigrationService/sqlMigrationServiceDetailsDialog'; import { SqlMigrationServiceDetailsDialog } from '../sqlMigrationService/sqlMigrationServiceDetailsDialog';
import { ConfirmCutoverDialog } from '../migrationCutover/confirmCutoverDialog'; import { ConfirmCutoverDialog } from '../migrationCutover/confirmCutoverDialog';
import { MigrationCutoverDialogModel } from '../migrationCutover/migrationCutoverDialogModel'; import { MigrationCutoverDialogModel } from '../migrationCutover/migrationCutoverDialogModel';
@@ -103,8 +103,8 @@ export class MigrationStatusDialog {
width: '360px' width: '360px'
}).component(); }).component();
this._disposables.push(this._searchBox.onTextChanged((value) => { this._disposables.push(this._searchBox.onTextChanged(async (value) => {
this.populateMigrationTable(); await this.populateMigrationTable();
})); }));
this._refresh = this._view.modelBuilder.button().withProps({ this._refresh = this._view.modelBuilder.button().withProps({
@@ -136,8 +136,8 @@ export class MigrationStatusDialog {
width: '220px' width: '220px'
}).component(); }).component();
this._disposables.push(this._statusDropdown.onValueChanged((value) => { this._disposables.push(this._statusDropdown.onValueChanged(async (value) => {
this.populateMigrationTable(); await this.populateMigrationTable();
})); }));
if (this._filter) { if (this._filter) {
@@ -204,16 +204,14 @@ export class MigrationStatusDialog {
await cutoverDialogModel.fetchStatus(); await cutoverDialogModel.fetchStatus();
const dialog = new ConfirmCutoverDialog(cutoverDialogModel); const dialog = new ConfirmCutoverDialog(cutoverDialogModel);
await dialog.initialize(); await dialog.initialize();
if (cutoverDialogModel.CutoverError) {
displayDialogErrorMessage(this._dialogObject, loc.MIGRATION_CUTOVER_ERROR, cutoverDialogModel.CutoverError);
}
} else { } else {
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_CUTOVER); await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_CUTOVER);
} }
} catch (e) { } catch (e) {
this._dialogObject.message = { displayDialogErrorMessage(this._dialogObject, loc.MIGRATION_CUTOVER_ERROR, e);
text: loc.MIGRATION_STATUS_REFRESH_ERROR,
description: e.message,
level: azdata.window.MessageLevel.Error
};
console.log(e); console.log(e);
} }
})); }));
@@ -273,12 +271,7 @@ export class MigrationStatusDialog {
await vscode.window.showInformationMessage(loc.DETAILS_COPIED); await vscode.window.showInformationMessage(loc.DETAILS_COPIED);
} catch (e) { } catch (e) {
this._dialogObject.message = { displayDialogErrorMessage(this._dialogObject, loc.MIGRATION_STATUS_REFRESH_ERROR, e);
text: loc.MIGRATION_STATUS_REFRESH_ERROR,
description: e.message,
level: azdata.window.MessageLevel.Error
};
console.log(e); console.log(e);
} }
})); }));
@@ -290,23 +283,22 @@ export class MigrationStatusDialog {
clearDialogMessage(this._dialogObject); clearDialogMessage(this._dialogObject);
const migration = this._model._migrations.find(migration => migration.migrationContext.id === migrationId); const migration = this._model._migrations.find(migration => migration.migrationContext.id === migrationId);
if (this.canCancelMigration(migration?.migrationContext.properties.migrationStatus)) { if (this.canCancelMigration(migration?.migrationContext.properties.migrationStatus)) {
vscode.window.showInformationMessage(loc.CANCEL_MIGRATION_CONFIRMATION, loc.YES, loc.NO).then(async (v) => { void vscode.window.showInformationMessage(loc.CANCEL_MIGRATION_CONFIRMATION, loc.YES, loc.NO).then(async (v) => {
if (v === loc.YES) { if (v === loc.YES) {
const cutoverDialogModel = new MigrationCutoverDialogModel(migration!); const cutoverDialogModel = new MigrationCutoverDialogModel(migration!);
await cutoverDialogModel.fetchStatus(); await cutoverDialogModel.fetchStatus();
await cutoverDialogModel.cancelMigration(); await cutoverDialogModel.cancelMigration();
if (cutoverDialogModel.CancelMigrationError) {
displayDialogErrorMessage(this._dialogObject, loc.MIGRATION_CANNOT_CANCEL, cutoverDialogModel.CancelMigrationError);
}
} }
}); });
} else { } else {
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_CANCEL); await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_CANCEL);
} }
} catch (e) { } catch (e) {
this._dialogObject.message = { displayDialogErrorMessage(this._dialogObject, loc.MIGRATION_CANCELLATION_ERROR, e);
text: loc.MIGRATION_CANCELLATION_ERROR,
description: e.message,
level: azdata.window.MessageLevel.Error
};
console.log(e); console.log(e);
} }
})); }));
@@ -508,12 +500,7 @@ export class MigrationStatusDialog {
this._model._migrations = await MigrationLocalStorage.getMigrationsBySourceConnections(currentConnection, true); this._model._migrations = await MigrationLocalStorage.getMigrationsBySourceConnections(currentConnection, true);
await this.populateMigrationTable(); await this.populateMigrationTable();
} catch (e) { } catch (e) {
this._dialogObject.message = { displayDialogErrorMessage(this._dialogObject, loc.MIGRATION_STATUS_REFRESH_ERROR, e);
text: loc.MIGRATION_STATUS_REFRESH_ERROR,
description: e.message,
level: azdata.window.MessageLevel.Error
};
console.log(e); console.log(e);
} finally { } finally {
this.isRefreshing = false; this.isRefreshing = false;

View File

@@ -249,9 +249,9 @@ export class SqlMigrationServiceDetailsDialog {
}) })
.component(); .component();
this._disposables.push(copyKey1Button.onDidClick((e) => { this._disposables.push(copyKey1Button.onDidClick(async (e) => {
vscode.env.clipboard.writeText(keys.authKey1); await vscode.env.clipboard.writeText(keys.authKey1);
vscode.window.showInformationMessage(constants.SERVICE_KEY1_COPIED_HELP); void vscode.window.showInformationMessage(constants.SERVICE_KEY1_COPIED_HELP);
})); }));
const copyKey2Button = view.modelBuilder const copyKey2Button = view.modelBuilder
@@ -265,9 +265,9 @@ export class SqlMigrationServiceDetailsDialog {
}) })
.component(); .component();
this._disposables.push(copyKey2Button.onDidClick((e) => { this._disposables.push(copyKey2Button.onDidClick(async (e) => {
vscode.env.clipboard.writeText(keys.authKey2); await vscode.env.clipboard.writeText(keys.authKey2);
vscode.window.showInformationMessage(constants.SERVICE_KEY2_COPIED_HELP); void vscode.window.showInformationMessage(constants.SERVICE_KEY2_COPIED_HELP);
})); }));
const refreshKey1Button = view.modelBuilder const refreshKey1Button = view.modelBuilder
@@ -296,7 +296,7 @@ export class SqlMigrationServiceDetailsDialog {
this._disposables.push(refreshKey2Button.onDidClick( this._disposables.push(refreshKey2Button.onDidClick(
async (e) => await this._regenerateAuthKey(view, migrationContext, AUTH_KEY2))); async (e) => await this._regenerateAuthKey(view, migrationContext, AUTH_KEY2)));
this._migrationServiceAuthKeyTable.updateProperties({ await this._migrationServiceAuthKeyTable.updateProperties({
dataValues: [ dataValues: [
[ [
{ value: constants.SERVICE_KEY1_LABEL }, { value: constants.SERVICE_KEY1_LABEL },

View File

@@ -40,13 +40,13 @@ class SQLMigration {
const selectedNotebook = input.selectedItems[0]; const selectedNotebook = input.selectedItems[0];
if (selectedNotebook) { if (selectedNotebook) {
try { try {
azdata.nb.showNotebookDocument(vscode.Uri.parse(`untitled: ${selectedNotebook.label}`), { await azdata.nb.showNotebookDocument(vscode.Uri.parse(`untitled: ${selectedNotebook.label}`), {
preview: false, preview: false,
initialContent: (await fs.readFile(selectedNotebook.notebookPath)).toString(), initialContent: (await fs.readFile(selectedNotebook.notebookPath)).toString(),
initialDirtyState: false initialDirtyState: false
}); });
} catch (e) { } catch (e) {
vscode.window.showErrorMessage(`${loc.NOTEBOOK_OPEN_ERROR} - ${e.toString()}`); void vscode.window.showErrorMessage(`${loc.NOTEBOOK_OPEN_ERROR} - ${e.toString()}`);
} }
input.hide(); input.hide();
} }

View File

@@ -59,7 +59,7 @@ export class MigrationLocalStorage {
} }
validMigrations.push(migration); validMigrations.push(migration);
} }
this.context.globalState.update(this.mementoToken, validMigrations); await this.context.globalState.update(this.mementoToken, validMigrations);
return result; return result;
} }
@@ -77,7 +77,7 @@ export class MigrationLocalStorage {
} }
} }
public static saveMigration( public static async saveMigration(
connectionProfile: azdata.connection.ConnectionProfile, connectionProfile: azdata.connection.ConnectionProfile,
migrationContext: DatabaseMigration, migrationContext: DatabaseMigration,
targetMI: SqlManagedInstance | SqlVMServer, targetMI: SqlManagedInstance | SqlVMServer,
@@ -85,7 +85,7 @@ export class MigrationLocalStorage {
subscription: azureResource.AzureResourceSubscription, subscription: azureResource.AzureResourceSubscription,
controller: SqlMigrationService, controller: SqlMigrationService,
asyncURL: string, asyncURL: string,
sessionId: string): void { sessionId: string): Promise<void> {
try { try {
let migrationMementos: MigrationContext[] = this.context.globalState.get(this.mementoToken) || []; let migrationMementos: MigrationContext[] = this.context.globalState.get(this.mementoToken) || [];
migrationMementos = migrationMementos.filter(m => m.migrationContext.id !== migrationContext.id); migrationMementos = migrationMementos.filter(m => m.migrationContext.id !== migrationContext.id);
@@ -99,14 +99,14 @@ export class MigrationLocalStorage {
asyncUrl: asyncURL, asyncUrl: asyncURL,
sessionId: sessionId sessionId: sessionId
}); });
this.context.globalState.update(this.mementoToken, migrationMementos); await this.context.globalState.update(this.mementoToken, migrationMementos);
} catch (e) { } catch (e) {
console.log(e); console.log(e);
} }
} }
public static clearMigrations() { public static async clearMigrations(): Promise<void> {
this.context.globalState.update(this.mementoToken, ([] as MigrationContext[])); await this.context.globalState.update(this.mementoToken, ([] as MigrationContext[]));
} }
public static removeMigrationSecrets(migration: DatabaseMigration): DatabaseMigration { public static removeMigrationSecrets(migration: DatabaseMigration): DatabaseMigration {
@@ -154,3 +154,13 @@ export enum ProvisioningState {
Succeeded = 'Succeeded', Succeeded = 'Succeeded',
Creating = 'Creating' Creating = 'Creating'
} }
export enum BackupFileInfoStatus {
Arrived = 'Arrived',
Uploading = 'Uploading',
Uploaded = 'Uploaded',
Restoring = 'Restoring',
Restored = 'Restored',
Canceled = 'Canceled',
Ignored = 'Ignored'
}

View File

@@ -43,7 +43,7 @@ export abstract class MigrationWizardPage {
return this.handleStateChange(e); return this.handleStateChange(e);
}); });
this.enableQueueProcessor(); await this.enableQueueProcessor();
} }
private queueActive = false; private queueActive = false;

View File

@@ -951,7 +951,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
} }
); );
MigrationLocalStorage.saveMigration( await MigrationLocalStorage.saveMigration(
currentConnection!, currentConnection!,
response.databaseMigration, response.databaseMigration,
this._targetServerInstance, this._targetServerInstance,
@@ -961,15 +961,15 @@ export class MigrationStateModel implements Model, vscode.Disposable {
response.asyncUrl, response.asyncUrl,
this._sessionId this._sessionId
); );
vscode.window.showInformationMessage(localize("sql.migration.starting.migration.message", 'Starting migration for database {0} to {1} - {2}', this._migrationDbs[i], this._targetServerInstance.name, this._targetDatabaseNames[i])); void vscode.window.showInformationMessage(localize("sql.migration.starting.migration.message", 'Starting migration for database {0} to {1} - {2}', this._migrationDbs[i], this._targetServerInstance.name, this._targetDatabaseNames[i]));
} }
} catch (e) { } catch (e) {
vscode.window.showErrorMessage( void vscode.window.showErrorMessage(
localize('sql.migration.starting.migration.error', "An error occurred while starting the migration: '{0}'", e.message)); localize('sql.migration.starting.migration.error', "An error occurred while starting the migration: '{0}'", e.message));
console.log(e); console.log(e);
} }
vscode.commands.executeCommand('sqlmigration.refreshMigrationTiles'); await vscode.commands.executeCommand('sqlmigration.refreshMigrationTiles');
} }
} }
} }

View File

@@ -88,11 +88,11 @@ export class AccountsSelectionPage extends MigrationWizardPage {
this.migrationStateModel._accountTenants = selectedAzureAccount.properties.tenants; this.migrationStateModel._accountTenants = selectedAzureAccount.properties.tenants;
this._accountTenantDropdown.values = await this.migrationStateModel.getTenantValues(); this._accountTenantDropdown.values = await this.migrationStateModel.getTenantValues();
selectDropDownIndex(this._accountTenantDropdown, 0); selectDropDownIndex(this._accountTenantDropdown, 0);
this._accountTenantFlexContainer.updateCssStyles({ await this._accountTenantFlexContainer.updateCssStyles({
'display': 'inline' 'display': 'inline'
}); });
} else { } else {
this._accountTenantFlexContainer.updateCssStyles({ await this._accountTenantFlexContainer.updateCssStyles({
'display': 'none' 'display': 'none'
}); });
} }
@@ -119,7 +119,7 @@ export class AccountsSelectionPage extends MigrationWizardPage {
this.wizard.message = { this.wizard.message = {
text: '' text: ''
}; };
this._azureAccountsDropdown.validate(); await this._azureAccountsDropdown.validate();
})); }));
const flexContainer = view.modelBuilder.flexContainer() const flexContainer = view.modelBuilder.flexContainer()

View File

@@ -126,9 +126,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
} }
}).component(); }).component();
this._disposables.push(this._networkShareButton.onDidChangeCheckedState((e) => { this._disposables.push(this._networkShareButton.onDidChangeCheckedState(async (e) => {
if (e) { if (e) {
this.switchNetworkContainerFields(NetworkContainerType.NETWORK_SHARE); await this.switchNetworkContainerFields(NetworkContainerType.NETWORK_SHARE);
} }
})); }));
@@ -141,9 +141,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
} }
}).component(); }).component();
this._disposables.push(this._blobContainerButton.onDidChangeCheckedState((e) => { this._disposables.push(this._blobContainerButton.onDidChangeCheckedState(async (e) => {
if (e) { if (e) {
this.switchNetworkContainerFields(NetworkContainerType.BLOB_CONTAINER); await this.switchNetworkContainerFields(NetworkContainerType.BLOB_CONTAINER);
} }
})); }));
@@ -273,8 +273,8 @@ export class DatabaseBackupPage extends MigrationWizardPage {
} }
return true; return true;
}).component(); }).component();
this._disposables.push(this._networkSharePath.onTextChanged((value) => { this._disposables.push(this._networkSharePath.onTextChanged(async (value) => {
this.validateFields(); await this.validateFields();
this.migrationStateModel._databaseBackup.networkShare.networkShareLocation = value; this.migrationStateModel._databaseBackup.networkShare.networkShareLocation = value;
})); }));
@@ -745,14 +745,14 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this._networkShareButton.checked = false; this._networkShareButton.checked = false;
this._networkTableContainer.display = 'none'; this._networkTableContainer.display = 'none';
this._networkShareContainer.updateCssStyles({ 'display': 'none' }); await this._networkShareContainer.updateCssStyles({ 'display': 'none' });
this._blobContainerButton.checked = false; this._blobContainerButton.checked = false;
this._blobTableContainer.display = 'none'; this._blobTableContainer.display = 'none';
this._blobContainer.updateCssStyles({ 'display': 'none' }); await this._blobContainer.updateCssStyles({ 'display': 'none' });
this._targetDatabaseContainer.updateCssStyles({ 'display': 'none' }); await this._targetDatabaseContainer.updateCssStyles({ 'display': 'none' });
this._networkShareStorageAccountDetails.updateCssStyles({ 'display': 'none' }); await this._networkShareStorageAccountDetails.updateCssStyles({ 'display': 'none' });
const connectionProfile = await this.migrationStateModel.getSourceConnectionProfile(); const connectionProfile = await this.migrationStateModel.getSourceConnectionProfile();
const queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>((await this.migrationStateModel.getSourceConnectionProfile()).providerId, azdata.DataProviderType.QueryProvider); const queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>((await this.migrationStateModel.getSourceConnectionProfile()).providerId, azdata.DataProviderType.QueryProvider);
const query = 'select SUSER_NAME()'; const query = 'select SUSER_NAME()';
@@ -798,9 +798,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
} }
return true; return true;
}).component(); }).component();
this._disposables.push(targetDatabaseInput.onTextChanged((value) => { this._disposables.push(targetDatabaseInput.onTextChanged(async (value) => {
this.migrationStateModel._targetDatabaseNames[index] = value.trim(); this.migrationStateModel._targetDatabaseNames[index] = value.trim();
this.validateFields(); await this.validateFields();
})); }));
this._networkShareTargetDatabaseNames.push(targetDatabaseInput); this._networkShareTargetDatabaseNames.push(targetDatabaseInput);
@@ -863,9 +863,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
if (selectedIndex > -1 && !blobResourceGroupErrorStrings.includes(value)) { if (selectedIndex > -1 && !blobResourceGroupErrorStrings.includes(value)) {
this.migrationStateModel._databaseBackup.blobs[index].resourceGroup = this.migrationStateModel.getAzureResourceGroup(selectedIndex); this.migrationStateModel._databaseBackup.blobs[index].resourceGroup = this.migrationStateModel.getAzureResourceGroup(selectedIndex);
await this.loadBlobStorageDropdown(index); await this.loadBlobStorageDropdown(index);
blobContainerStorageAccountDropdown.updateProperties({ enabled: true }); await blobContainerStorageAccountDropdown.updateProperties({ enabled: true });
} else { } else {
this.disableBlobTableDropdowns(index, constants.RESOURCE_GROUP); await this.disableBlobTableDropdowns(index, constants.RESOURCE_GROUP);
} }
})); }));
this._blobContainerResourceGroupDropdowns.push(blobContainerResourceDropdown); this._blobContainerResourceGroupDropdowns.push(blobContainerResourceDropdown);
@@ -875,9 +875,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
if (selectedIndex > -1 && !blobStorageAccountErrorStrings.includes(value)) { if (selectedIndex > -1 && !blobStorageAccountErrorStrings.includes(value)) {
this.migrationStateModel._databaseBackup.blobs[index].storageAccount = this.migrationStateModel.getStorageAccount(selectedIndex); this.migrationStateModel._databaseBackup.blobs[index].storageAccount = this.migrationStateModel.getStorageAccount(selectedIndex);
await this.loadBlobContainerDropdown(index); await this.loadBlobContainerDropdown(index);
blobContainerDropdown.updateProperties({ enabled: true }); await blobContainerDropdown.updateProperties({ enabled: true });
} else { } else {
this.disableBlobTableDropdowns(index, constants.STORAGE_ACCOUNT); await this.disableBlobTableDropdowns(index, constants.STORAGE_ACCOUNT);
} }
})); }));
this._blobContainerStorageAccountDropdowns.push(blobContainerStorageAccountDropdown); this._blobContainerStorageAccountDropdowns.push(blobContainerStorageAccountDropdown);
@@ -888,10 +888,10 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this.migrationStateModel._databaseBackup.blobs[index].blobContainer = this.migrationStateModel.getBlobContainer(selectedIndex); this.migrationStateModel._databaseBackup.blobs[index].blobContainer = this.migrationStateModel.getBlobContainer(selectedIndex);
if (this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE) { if (this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE) {
await this.loadBlobLastBackupFileDropdown(index); await this.loadBlobLastBackupFileDropdown(index);
blobContainerLastBackupFileDropdown.updateProperties({ enabled: true }); await blobContainerLastBackupFileDropdown.updateProperties({ enabled: true });
} }
} else { } else {
this.disableBlobTableDropdowns(index, constants.BLOB_CONTAINER); await this.disableBlobTableDropdowns(index, constants.BLOB_CONTAINER);
} }
})); }));
this._blobContainerDropdowns.push(blobContainerDropdown); this._blobContainerDropdowns.push(blobContainerDropdown);
@@ -1062,7 +1062,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
protected async handleStateChange(e: StateChangeEvent): Promise<void> { protected async handleStateChange(e: StateChangeEvent): Promise<void> {
} }
private switchNetworkContainerFields(containerType: NetworkContainerType): void { private async switchNetworkContainerFields(containerType: NetworkContainerType): Promise<void> {
this.wizard.message = { this.wizard.message = {
text: '', text: '',
level: azdata.window.MessageLevel.Error level: azdata.window.MessageLevel.Error
@@ -1070,10 +1070,10 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this.wizard.nextButton.enabled = true; this.wizard.nextButton.enabled = true;
this.migrationStateModel._databaseBackup.networkContainerType = containerType; this.migrationStateModel._databaseBackup.networkContainerType = containerType;
this._blobContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.BLOB_CONTAINER) ? 'inline' : 'none' }); await this._blobContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.BLOB_CONTAINER) ? 'inline' : 'none' });
this._networkShareContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none' }); await this._networkShareContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none' });
this._networkShareStorageAccountDetails.updateCssStyles({ 'display': (containerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none' }); await this._networkShareStorageAccountDetails.updateCssStyles({ 'display': (containerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none' });
this._targetDatabaseContainer.updateCssStyles({ 'display': 'inline' }); await this._targetDatabaseContainer.updateCssStyles({ 'display': 'inline' });
this._networkTableContainer.display = (containerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none'; this._networkTableContainer.display = (containerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none';
this._blobTableContainer.display = (containerType === NetworkContainerType.BLOB_CONTAINER) ? 'inline' : 'none'; this._blobTableContainer.display = (containerType === NetworkContainerType.BLOB_CONTAINER) ? 'inline' : 'none';
@@ -1083,19 +1083,19 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this._blobContainerTargetDatabaseNames[index].value = v; this._blobContainerTargetDatabaseNames[index].value = v;
}); });
this._windowsUserAccountText.updateProperties({ await this._windowsUserAccountText.updateProperties({
required: containerType === NetworkContainerType.NETWORK_SHARE required: containerType === NetworkContainerType.NETWORK_SHARE
}); });
this._passwordText.updateProperties({ await this._passwordText.updateProperties({
required: containerType === NetworkContainerType.NETWORK_SHARE required: containerType === NetworkContainerType.NETWORK_SHARE
}); });
this._sqlSourceUsernameInput.updateProperties({ await this._sqlSourceUsernameInput.updateProperties({
required: containerType === NetworkContainerType.NETWORK_SHARE required: containerType === NetworkContainerType.NETWORK_SHARE
}); });
this._sqlSourcepassword.updateProperties({ await this._sqlSourcepassword.updateProperties({
required: containerType === NetworkContainerType.NETWORK_SHARE required: containerType === NetworkContainerType.NETWORK_SHARE
}); });
this.validateFields(); await this.validateFields();
} }
@@ -1132,9 +1132,8 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this.migrationStateModel._databaseBackup.subscription = this.migrationStateModel._targetSubscription; this.migrationStateModel._databaseBackup.subscription = this.migrationStateModel._targetSubscription;
await this.loadNetworkStorageResourceGroup();
this.loadNetworkStorageResourceGroup(); await this.loadBlobResourceGroup();
this.loadBlobResourceGroup();
} }
private async loadNetworkStorageResourceGroup(): Promise<void> { private async loadNetworkStorageResourceGroup(): Promise<void> {
@@ -1219,24 +1218,24 @@ export class DatabaseBackupPage extends MigrationWizardPage {
return v.value === undefined || errorStrings.includes((<azdata.CategoryValue>v.value)?.displayName); return v.value === undefined || errorStrings.includes((<azdata.CategoryValue>v.value)?.displayName);
} }
private disableBlobTableDropdowns(rowIndex: number, columnName: string): void { private async disableBlobTableDropdowns(rowIndex: number, columnName: string): Promise<void> {
const dropdownProps = { enabled: false, loading: false }; const dropdownProps = { enabled: false, loading: false };
const createDropdownValuesWithPrereq = (displayName: string, name: string = '') => [{ displayName, name }]; const createDropdownValuesWithPrereq = (displayName: string, name: string = '') => [{ displayName, name }];
if (this.migrationStateModel._databaseBackup?.migrationMode === MigrationMode.OFFLINE) { if (this.migrationStateModel._databaseBackup?.migrationMode === MigrationMode.OFFLINE) {
this._blobContainerLastBackupFileDropdowns[rowIndex].values = createDropdownValuesWithPrereq(constants.SELECT_BLOB_CONTAINER); this._blobContainerLastBackupFileDropdowns[rowIndex].values = createDropdownValuesWithPrereq(constants.SELECT_BLOB_CONTAINER);
selectDropDownIndex(this._blobContainerLastBackupFileDropdowns[rowIndex], 0); selectDropDownIndex(this._blobContainerLastBackupFileDropdowns[rowIndex], 0);
this._blobContainerLastBackupFileDropdowns[rowIndex]?.updateProperties(dropdownProps); await this._blobContainerLastBackupFileDropdowns[rowIndex]?.updateProperties(dropdownProps);
} }
if (columnName === constants.BLOB_CONTAINER) { return; } if (columnName === constants.BLOB_CONTAINER) { return; }
this._blobContainerDropdowns[rowIndex].values = createDropdownValuesWithPrereq(constants.SELECT_STORAGE_ACCOUNT); this._blobContainerDropdowns[rowIndex].values = createDropdownValuesWithPrereq(constants.SELECT_STORAGE_ACCOUNT);
selectDropDownIndex(this._blobContainerDropdowns[rowIndex], 0); selectDropDownIndex(this._blobContainerDropdowns[rowIndex], 0);
this._blobContainerDropdowns[rowIndex].updateProperties(dropdownProps); await this._blobContainerDropdowns[rowIndex].updateProperties(dropdownProps);
if (columnName === constants.STORAGE_ACCOUNT) { return; } if (columnName === constants.STORAGE_ACCOUNT) { return; }
this._blobContainerStorageAccountDropdowns[rowIndex].values = createDropdownValuesWithPrereq(constants.SELECT_RESOURCE_GROUP); this._blobContainerStorageAccountDropdowns[rowIndex].values = createDropdownValuesWithPrereq(constants.SELECT_RESOURCE_GROUP);
selectDropDownIndex(this._blobContainerStorageAccountDropdowns[rowIndex], 0); selectDropDownIndex(this._blobContainerStorageAccountDropdowns[rowIndex], 0);
this._blobContainerStorageAccountDropdowns[rowIndex].updateProperties(dropdownProps); await this._blobContainerStorageAccountDropdowns[rowIndex].updateProperties(dropdownProps);
} }
} }

View File

@@ -288,8 +288,8 @@ export class DatabaseSelectorPage extends MigrationWizardPage {
).component(); ).component();
await this._databaseSelectorTable.setDataValues(this._databaseTableValues); await this._databaseSelectorTable.setDataValues(this._databaseTableValues);
this._disposables.push(this._databaseSelectorTable.onDataChanged(() => { this._disposables.push(this._databaseSelectorTable.onDataChanged(async () => {
this._dbCount.updateProperties({ await this._dbCount.updateProperties({
'value': constants.DATABASES_SELECTED(this.selectedDbs().length, this._databaseTableValues.length) 'value': constants.DATABASES_SELECTED(this.selectedDbs().length, this._databaseTableValues.length)
}); });
})); }));

View File

@@ -106,7 +106,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
this._subscription.value = this.migrationStateModel._targetSubscription.name; this._subscription.value = this.migrationStateModel._targetSubscription.name;
this._location.value = await getLocationDisplayName(this.migrationStateModel._targetServerInstance.location); this._location.value = await getLocationDisplayName(this.migrationStateModel._targetServerInstance.location);
this._dmsInfoContainer.display = (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE && this.migrationStateModel._sqlMigrationService) ? 'inline' : 'none'; this._dmsInfoContainer.display = (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE && this.migrationStateModel._sqlMigrationService) ? 'inline' : 'none';
this.loadResourceGroupDropdown(); await this.loadResourceGroupDropdown();
this.wizard.registerNavigationValidator((pageChangeInfo) => { this.wizard.registerNavigationValidator((pageChangeInfo) => {
if (pageChangeInfo.newPage < pageChangeInfo.lastPage) { if (pageChangeInfo.newPage < pageChangeInfo.lastPage) {
this.wizard.message = { this.wizard.message = {
@@ -337,7 +337,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
this._disposables.push(this._copy1.onDidClick(async (e) => { this._disposables.push(this._copy1.onDidClick(async (e) => {
await vscode.env.clipboard.writeText(<string>this._authKeyTable.dataValues![0][1].value); await vscode.env.clipboard.writeText(<string>this._authKeyTable.dataValues![0][1].value);
vscode.window.showInformationMessage(constants.SERVICE_KEY1_COPIED_HELP); void vscode.window.showInformationMessage(constants.SERVICE_KEY1_COPIED_HELP);
})); }));
this._copy2 = this._view.modelBuilder.button().withProps({ this._copy2 = this._view.modelBuilder.button().withProps({
@@ -348,7 +348,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
this._disposables.push(this._copy2.onDidClick(async (e) => { this._disposables.push(this._copy2.onDidClick(async (e) => {
await vscode.env.clipboard.writeText(<string>this._authKeyTable.dataValues![1][1].value); await vscode.env.clipboard.writeText(<string>this._authKeyTable.dataValues![1][1].value);
vscode.window.showInformationMessage(constants.SERVICE_KEY2_COPIED_HELP); void vscode.window.showInformationMessage(constants.SERVICE_KEY2_COPIED_HELP);
})); }));
this._refresh1 = this._view.modelBuilder.button().withProps({ this._refresh1 = this._view.modelBuilder.button().withProps({
@@ -500,12 +500,12 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
const state = migrationService.properties.integrationRuntimeState; const state = migrationService.properties.integrationRuntimeState;
if (state === 'Online') { if (state === 'Online') {
this._dmsStatusInfoBox.updateProperties(<azdata.InfoBoxComponentProperties>{ await this._dmsStatusInfoBox.updateProperties(<azdata.InfoBoxComponentProperties>{
text: constants.SERVICE_READY(this.migrationStateModel._sqlMigrationService!.name, this.migrationStateModel._nodeNames.join(', ')), text: constants.SERVICE_READY(this.migrationStateModel._sqlMigrationService!.name, this.migrationStateModel._nodeNames.join(', ')),
style: 'success' style: 'success'
}); });
} else { } else {
this._dmsStatusInfoBox.updateProperties(<azdata.InfoBoxComponentProperties>{ await this._dmsStatusInfoBox.updateProperties(<azdata.InfoBoxComponentProperties>{
text: constants.SERVICE_NOT_READY(this.migrationStateModel._sqlMigrationService!.name), text: constants.SERVICE_NOT_READY(this.migrationStateModel._sqlMigrationService!.name),
style: 'error' style: 'error'
}); });

View File

@@ -92,8 +92,8 @@ export class SKURecommendationPage extends MigrationWizardPage {
width: 130 width: 130
}).component(); }).component();
this._disposables.push(refreshAssessmentButton.onDidClick(() => { this._disposables.push(refreshAssessmentButton.onDidClick(async () => {
this.constructDetails(); await this.constructDetails();
})); }));
const chooseYourTargetText = this._view.modelBuilder.text().withProps({ const chooseYourTargetText = this._view.modelBuilder.text().withProps({
@@ -225,10 +225,10 @@ export class SKURecommendationPage extends MigrationWizardPage {
}); });
}); });
this._disposables.push(this._rbg.onSelectionChanged((value) => { this._disposables.push(this._rbg.onSelectionChanged(async (value) => {
if (value) { if (value) {
this.assessmentGroupContainer.display = 'inline'; this.assessmentGroupContainer.display = 'inline';
this.changeTargetType(value.cardId); await this.changeTargetType(value.cardId);
} }
})); }));
@@ -427,7 +427,7 @@ export class SKURecommendationPage extends MigrationWizardPage {
} }
private changeTargetType(newTargetType: string) { private async changeTargetType(newTargetType: string) {
// remove assessed databases that have been removed from the source selection list // remove assessed databases that have been removed from the source selection list
const miDbs = this.migrationStateModel._miDbs.filter( const miDbs = this.migrationStateModel._miDbs.filter(
db => this.migrationStateModel._databaseAssessment.findIndex( db => this.migrationStateModel._databaseAssessment.findIndex(
@@ -452,7 +452,7 @@ export class SKURecommendationPage extends MigrationWizardPage {
} }
this.migrationStateModel.refreshDatabaseBackupPage = true; this.migrationStateModel.refreshDatabaseBackupPage = true;
this._targetContainer.display = (this.migrationStateModel._migrationDbs.length === 0) ? 'none' : 'inline'; this._targetContainer.display = (this.migrationStateModel._migrationDbs.length === 0) ? 'none' : 'inline';
this.populateResourceInstanceDropdown(); await this.populateResourceInstanceDropdown();
} }
private async constructDetails(): Promise<void> { private async constructDetails(): Promise<void> {
@@ -460,8 +460,8 @@ export class SKURecommendationPage extends MigrationWizardPage {
text: '', text: '',
level: azdata.window.MessageLevel.Error level: azdata.window.MessageLevel.Error
}; };
this._assessmentComponent.updateCssStyles({ display: 'block' }); await this._assessmentComponent.updateCssStyles({ display: 'block' });
this._formContainer.component().updateCssStyles({ display: 'none' }); await this._formContainer.component().updateCssStyles({ display: 'none' });
this._assessmentLoader.loading = true; this._assessmentLoader.loading = true;
const serverName = (await this.migrationStateModel.getSourceConnectionProfile()).serverName; const serverName = (await this.migrationStateModel.getSourceConnectionProfile()).serverName;
@@ -499,10 +499,10 @@ errorId: ${e.errorId}
console.log(e); console.log(e);
} }
this.refreshCardText(); await this.refreshCardText();
this._assessmentLoader.loading = false; this._assessmentLoader.loading = false;
this._assessmentComponent.updateCssStyles({ display: 'none' }); await this._assessmentComponent.updateCssStyles({ display: 'none' });
this._formContainer.component().updateCssStyles({ display: 'block' }); await this._formContainer.component().updateCssStyles({ display: 'block' });
} }
private async populateSubscriptionDropdown(): Promise<void> { private async populateSubscriptionDropdown(): Promise<void> {
@@ -612,14 +612,14 @@ errorId: ${e.errorId}
if (this.migrationStateModel._runAssessments) { if (this.migrationStateModel._runAssessments) {
await this.constructDetails(); await this.constructDetails();
} }
this._assessmentComponent.updateCssStyles({ await this._assessmentComponent.updateCssStyles({
display: 'none' display: 'none'
}); });
this._formContainer.component().updateCssStyles({ await this._formContainer.component().updateCssStyles({
display: 'block' display: 'block'
}); });
this.populateSubscriptionDropdown(); await this.populateSubscriptionDropdown();
this.wizard.nextButton.enabled = true; this.wizard.nextButton.enabled = true;
} }
@@ -637,16 +637,16 @@ errorId: ${e.errorId}
protected async handleStateChange(e: StateChangeEvent): Promise<void> { protected async handleStateChange(e: StateChangeEvent): Promise<void> {
} }
public refreshDatabaseCount(selectedDbs: string[]): void { public async refreshDatabaseCount(selectedDbs: string[]): Promise<void> {
this.wizard.message = { this.wizard.message = {
text: '', text: '',
level: azdata.window.MessageLevel.Error level: azdata.window.MessageLevel.Error
}; };
this.migrationStateModel._migrationDbs = selectedDbs; this.migrationStateModel._migrationDbs = selectedDbs;
this.refreshCardText(); await this.refreshCardText();
} }
public refreshCardText(): void { public async refreshCardText(): Promise<void> {
this._rbgLoader.loading = true; this._rbgLoader.loading = true;
if (this._rbg.selectedCardId === MigrationTargetType.SQLMI) { if (this._rbg.selectedCardId === MigrationTargetType.SQLMI) {
this.migrationStateModel._migrationDbs = this.migrationStateModel._miDbs; this.migrationStateModel._migrationDbs = this.migrationStateModel._miDbs;
@@ -667,20 +667,20 @@ errorId: ${e.errorId}
const vmCardText = constants.CAN_BE_MIGRATED(dbCount, dbCount); const vmCardText = constants.CAN_BE_MIGRATED(dbCount, dbCount);
this._rbg.cards[1].descriptions[1].textValue = vmCardText; this._rbg.cards[1].descriptions[1].textValue = vmCardText;
this._rbg.updateProperties({ await this._rbg.updateProperties({
cards: this._rbg.cards cards: this._rbg.cards
}); });
} else { } else {
this._rbg.cards[0].descriptions[1].textValue = ''; this._rbg.cards[0].descriptions[1].textValue = '';
this._rbg.cards[1].descriptions[1].textValue = ''; this._rbg.cards[1].descriptions[1].textValue = '';
this._rbg.updateProperties({ await this._rbg.updateProperties({
cards: this._rbg.cards cards: this._rbg.cards
}); });
} }
if (this._rbg.selectedCardId) { if (this._rbg.selectedCardId) {
this.changeTargetType(this._rbg.selectedCardId); await this.changeTargetType(this._rbg.selectedCardId);
} }
this._rbgLoader.loading = false; this._rbgLoader.loading = false;

View File

@@ -60,7 +60,7 @@ export class SqlSourceConfigurationPage extends MigrationWizardPage {
const username = results.rows[0][0].displayValue; const username = results.rows[0][0].displayValue;
this.migrationStateModel._authenticationType = connectionProfile.authenticationType === 'SqlLogin' ? MigrationSourceAuthenticationType.Sql : connectionProfile.authenticationType === 'Integrated' ? MigrationSourceAuthenticationType.Integrated : undefined!; this.migrationStateModel._authenticationType = connectionProfile.authenticationType === 'SqlLogin' ? MigrationSourceAuthenticationType.Sql : connectionProfile.authenticationType === 'Integrated' ? MigrationSourceAuthenticationType.Integrated : undefined!;
const sourceCredText = createHeadingTextComponent(this._view, constants.SOURCE_CREDENTIALS); const sourceCredText = await createHeadingTextComponent(this._view, constants.SOURCE_CREDENTIALS);
const enterYourCredText = createLabelTextComponent( const enterYourCredText = createLabelTextComponent(
this._view, this._view,

View File

@@ -56,8 +56,8 @@ export class SummaryPage extends MigrationWizardPage {
} }
}).component(); }).component();
this._disposables.push(targetDatabaseHyperlink.onDidClick(e => { this._disposables.push(targetDatabaseHyperlink.onDidClick(async e => {
targetDatabaseSummary.initialize(); await targetDatabaseSummary.initialize();
})); }));
const targetDatabaseRow = this._view.modelBuilder.flexContainer() const targetDatabaseRow = this._view.modelBuilder.flexContainer()
@@ -87,26 +87,26 @@ export class SummaryPage extends MigrationWizardPage {
this._flexContainer.addItems( this._flexContainer.addItems(
[ [
createHeadingTextComponent(this._view, constants.ACCOUNTS_SELECTION_PAGE_TITLE), await createHeadingTextComponent(this._view, constants.ACCOUNTS_SELECTION_PAGE_TITLE),
createInformationRow(this._view, constants.ACCOUNTS_SELECTION_PAGE_TITLE, this.migrationStateModel._azureAccount.displayInfo.displayName), createInformationRow(this._view, constants.ACCOUNTS_SELECTION_PAGE_TITLE, this.migrationStateModel._azureAccount.displayInfo.displayName),
createHeadingTextComponent(this._view, constants.SOURCE_DATABASES), await createHeadingTextComponent(this._view, constants.SOURCE_DATABASES),
targetDatabaseRow, targetDatabaseRow,
createHeadingTextComponent(this._view, constants.SKU_RECOMMENDATION_PAGE_TITLE), await createHeadingTextComponent(this._view, constants.SKU_RECOMMENDATION_PAGE_TITLE),
createInformationRow(this._view, constants.SKU_RECOMMENDATION_PAGE_TITLE, (this.migrationStateModel._targetType === MigrationTargetType.SQLVM) ? constants.SUMMARY_VM_TYPE : constants.SUMMARY_MI_TYPE), createInformationRow(this._view, constants.SKU_RECOMMENDATION_PAGE_TITLE, (this.migrationStateModel._targetType === MigrationTargetType.SQLVM) ? constants.SUMMARY_VM_TYPE : constants.SUMMARY_MI_TYPE),
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name), createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name),
createInformationRow(this._view, constants.LOCATION, await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.location)), createInformationRow(this._view, constants.LOCATION, await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.location)),
createInformationRow(this._view, constants.RESOURCE_GROUP, getResourceGroupFromId(this.migrationStateModel._targetServerInstance.id)), createInformationRow(this._view, constants.RESOURCE_GROUP, getResourceGroupFromId(this.migrationStateModel._targetServerInstance.id)),
createInformationRow(this._view, (this.migrationStateModel._targetType === MigrationTargetType.SQLVM) ? constants.SUMMARY_VM_TYPE : constants.SUMMARY_MI_TYPE, await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.name!)), createInformationRow(this._view, (this.migrationStateModel._targetType === MigrationTargetType.SQLVM) ? constants.SUMMARY_VM_TYPE : constants.SUMMARY_MI_TYPE, await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.name!)),
createHeadingTextComponent(this._view, constants.DATABASE_BACKUP_MIGRATION_MODE_LABEL), await createHeadingTextComponent(this._view, constants.DATABASE_BACKUP_MIGRATION_MODE_LABEL),
createInformationRow(this._view, constants.MODE, this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.ONLINE ? constants.DATABASE_BACKUP_MIGRATION_MODE_ONLINE_LABEL : constants.DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_LABEL), createInformationRow(this._view, constants.MODE, this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.ONLINE ? constants.DATABASE_BACKUP_MIGRATION_MODE_ONLINE_LABEL : constants.DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_LABEL),
createHeadingTextComponent(this._view, constants.DATABASE_BACKUP_PAGE_TITLE), await createHeadingTextComponent(this._view, constants.DATABASE_BACKUP_PAGE_TITLE),
await this.createNetworkContainerRows(), await this.createNetworkContainerRows(),
createHeadingTextComponent(this._view, constants.IR_PAGE_TITLE), await createHeadingTextComponent(this._view, constants.IR_PAGE_TITLE),
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name), createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name),
createInformationRow(this._view, constants.LOCATION, this.migrationStateModel._sqlMigrationService?.location!), createInformationRow(this._view, constants.LOCATION, this.migrationStateModel._sqlMigrationService?.location!),
createInformationRow(this._view, constants.RESOURCE_GROUP, this.migrationStateModel._sqlMigrationService?.properties?.resourceGroup!), createInformationRow(this._view, constants.RESOURCE_GROUP, this.migrationStateModel._sqlMigrationService?.properties?.resourceGroup!),
@@ -140,7 +140,7 @@ export class SummaryPage extends MigrationWizardPage {
createInformationRow(this._view, constants.BACKUP_LOCATION, constants.NETWORK_SHARE), createInformationRow(this._view, constants.BACKUP_LOCATION, constants.NETWORK_SHARE),
createInformationRow(this._view, constants.NETWORK_SHARE, this.migrationStateModel._databaseBackup.networkShare.networkShareLocation), createInformationRow(this._view, constants.NETWORK_SHARE, this.migrationStateModel._databaseBackup.networkShare.networkShareLocation),
createInformationRow(this._view, constants.USER_ACCOUNT, this.migrationStateModel._databaseBackup.networkShare.windowsUser), createInformationRow(this._view, constants.USER_ACCOUNT, this.migrationStateModel._databaseBackup.networkShare.windowsUser),
createHeadingTextComponent(this._view, constants.AZURE_STORAGE_ACCOUNT_TO_UPLOAD_BACKUPS), await createHeadingTextComponent(this._view, constants.AZURE_STORAGE_ACCOUNT_TO_UPLOAD_BACKUPS),
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._databaseBackup.subscription.name), createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._databaseBackup.subscription.name),
createInformationRow(this._view, constants.LOCATION, this.migrationStateModel._databaseBackup.networkShare.storageAccount.location), createInformationRow(this._view, constants.LOCATION, this.migrationStateModel._databaseBackup.networkShare.storageAccount.location),
createInformationRow(this._view, constants.RESOURCE_GROUP, this.migrationStateModel._databaseBackup.networkShare.storageAccount.resourceGroup!), createInformationRow(this._view, constants.RESOURCE_GROUP, this.migrationStateModel._databaseBackup.networkShare.storageAccount.resourceGroup!),

View File

@@ -30,7 +30,7 @@ export class WizardController {
if (api) { if (api) {
this._model = new MigrationStateModel(this.extensionContext, connectionId, api.sqlMigration); this._model = new MigrationStateModel(this.extensionContext, connectionId, api.sqlMigration);
this.extensionContext.subscriptions.push(this._model); this.extensionContext.subscriptions.push(this._model);
this.createWizard(this._model); await this.createWizard(this._model);
} }
} }
@@ -170,16 +170,15 @@ export function createInformationRow(view: azdata.ModelView, label: string, valu
.component(); .component();
} }
export function createHeadingTextComponent(view: azdata.ModelView, value: string): azdata.TextComponent { export async function createHeadingTextComponent(view: azdata.ModelView, value: string): Promise<azdata.TextComponent> {
const component = createTextCompononent(view, value); const component = createTextCompononent(view, value);
component.updateCssStyles({ await component.updateCssStyles({
'font-size': '13px', 'font-size': '13px',
'font-weight': 'bold', 'font-weight': 'bold',
}); });
return component; return component;
} }
export function createLabelTextComponent(view: azdata.ModelView, value: string, styles: { [key: string]: string; } = { 'width': '300px' }): azdata.TextComponent { export function createLabelTextComponent(view: azdata.ModelView, value: string, styles: { [key: string]: string; } = { 'width': '300px' }): azdata.TextComponent {
const component = createTextCompononent(view, value, styles); const component = createTextCompononent(view, value, styles);
return component; return component;