[Sql Migration] Stabilize save and close logic and fix related ux bugs (#18579)

* add loadSavedInfo function in stateMachine; only open wizard if didLoadSavedInfo

* * add loadSavedInfo function in stateMachine; only open wizard if didLoadSavedInfo
* replaced savedInfo.miggrationServiceId string with sqlMigrationServer object
* selectDatbasesFromList helper function to check previously selected dbs in dbSelectorPage and sqlDatabaseTree

* * remove savedInfo references from targetSelectionPage, migrationModePage
* add selectDefaultDropdownValue helper to stateMachine to handle unify savedInfo selection logic
* add updateDropdownLoadingStatus to targetSelectionPage
* check if values exist before making api calls in statemachine

* removed savedInfo references from databaseBackupPage, integrationRuntimePage

* databaseBackupPage - targetDatabaseNames, networkShares, blobs need to rely on savedInfo as user may update the list of migrationdbs during the retry/saveAndClose

* re-add serverAssessments to savedInfo; only getAssessments if it does not exist or needs to be updated; fix networkShare type savedInfo

* rename _assessmentDbs to _databasesForAssessment; _migrationDbs to _databasesForMigration

* load blobs/networkshares savedinfo; move selectDefaultDropdownValue to utils

* fix selectDefaultDropdownValue; refreshDatabaseBackupPage when user changes target subscription or location
This commit is contained in:
Rachel Kim
2022-03-04 16:00:44 -08:00
committed by GitHub
parent c9aa3e9f4b
commit 33259764f7
17 changed files with 621 additions and 643 deletions

View File

@@ -6,15 +6,14 @@
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { EOL } from 'os';
import { getStorageAccountAccessKeys, SqlManagedInstance, SqlVMServer, Subscription } from '../api/azure';
import { getStorageAccountAccessKeys } from '../api/azure';
import { MigrationWizardPage } from '../models/migrationWizardPage';
import { Blob, MigrationMode, MigrationSourceAuthenticationType, MigrationStateModel, MigrationTargetType, NetworkContainerType, NetworkShare, Page, StateChangeEvent } from '../models/stateMachine';
import { Blob, MigrationMode, MigrationSourceAuthenticationType, MigrationStateModel, MigrationTargetType, NetworkContainerType, NetworkShare, StateChangeEvent } from '../models/stateMachine';
import * as constants from '../constants/strings';
import { IconPathHelper } from '../constants/iconPathHelper';
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
import { findDropDownItemIndex, selectDropDownIndex } from '../api/utils';
import { findDropDownItemIndex, selectDropDownIndex, selectDefaultDropdownValue } from '../api/utils';
import { logError, TelemetryViews } from '../telemtery';
import { azureResource } from 'azureResource';
import * as styles from '../constants/styles';
const WIZARD_TABLE_COLUMN_WIDTH = '200px';
@@ -128,6 +127,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
.withProps({
name: buttonGroup,
label: constants.DATABASE_BACKUP_NC_NETWORK_SHARE_RADIO_LABEL,
checked: this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE,
CSSStyles: {
...styles.BODY_CSS,
'margin': '0'
@@ -144,6 +144,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
.withProps({
name: buttonGroup,
label: constants.DATABASE_BACKUP_NC_BLOB_STORAGE_RADIO_LABEL,
checked: this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.BLOB_CONTAINER,
CSSStyles: {
...styles.BODY_CSS,
'margin': '0'
@@ -298,9 +299,6 @@ export class DatabaseBackupPage extends MigrationWizardPage {
}
return true;
}).component();
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
this._windowsUserAccountText.value = this.migrationStateModel.savedInfo.networkShares[0].windowsUser;
}
this._disposables.push(this._windowsUserAccountText.onTextChanged((value) => {
for (let i = 0; i < this.migrationStateModel._databaseBackup.networkShares.length; i++) {
this.migrationStateModel._databaseBackup.networkShares[i].windowsUser = value;
@@ -545,7 +543,11 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this._networkTableContainer = this._view.modelBuilder.flexContainer().withItems([
networkShareTableText,
this._networkShareTargetDatabaseNamesTable
]).component();
]).withProps({
CSSStyles: {
'display': 'none',
}
}).component();
const allFieldsRequiredLabel = this._view.modelBuilder.text()
.withProps({
@@ -559,7 +561,11 @@ export class DatabaseBackupPage extends MigrationWizardPage {
blobTableText,
allFieldsRequiredLabel,
this._blobContainerTargetDatabaseNamesTable
]).component();
]).withProps({
CSSStyles: {
'display': 'none',
}
}).component();
const container = this._view.modelBuilder.flexContainer().withLayout({
flexFlow: 'column'
@@ -567,7 +573,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this._networkTableContainer,
this._blobTableContainer
]).withProps({
display: 'none'
CSSStyles: {
'display': 'none',
}
}).component();
return container;
}
@@ -736,18 +744,8 @@ export class DatabaseBackupPage extends MigrationWizardPage {
}
public async onPageEnter(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
if (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup) {
this.migrationStateModel._databaseBackup.networkContainerType = <NetworkContainerType>this.migrationStateModel.savedInfo.networkContainerType;
this.migrationStateModel._databaseBackup.networkShares = this.migrationStateModel.savedInfo.networkShares;
this.migrationStateModel._databaseBackup.subscription = <Subscription>this.migrationStateModel.savedInfo.targetSubscription;
this.migrationStateModel._databaseBackup.blobs = this.migrationStateModel.savedInfo.blobs;
this.migrationStateModel._targetDatabaseNames = this.migrationStateModel.savedInfo.targetDatabaseNames;
}
if (this.migrationStateModel.refreshDatabaseBackupPage) {
try {
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
this.migrationStateModel._migrationDbs = this.migrationStateModel.savedInfo.databaseList;
}
const isOfflineMigration = this.migrationStateModel._databaseBackup?.migrationMode === MigrationMode.OFFLINE;
const lastBackupFileColumnIndex = this._blobContainerTargetDatabaseNamesTable.columns.length - 1;
this._blobContainerTargetDatabaseNamesTable.columns[lastBackupFileColumnIndex].hidden = !isOfflineMigration;
@@ -755,30 +753,8 @@ export class DatabaseBackupPage extends MigrationWizardPage {
column.width = isOfflineMigration ? WIZARD_TABLE_COLUMN_WIDTH_SMALL : WIZARD_TABLE_COLUMN_WIDTH;
});
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
if (this.migrationStateModel.savedInfo.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
this._networkShareButton.checked = true;
} else {
this._networkShareButton.checked = false;
this._networkTableContainer.display = 'none';
await this._networkShareContainer.updateCssStyles({ 'display': 'none' });
}
}
await this.switchNetworkContainerFields(this.migrationStateModel._databaseBackup.networkContainerType);
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
if (this.migrationStateModel.savedInfo.networkContainerType === NetworkContainerType.BLOB_CONTAINER) {
this._blobContainerButton.checked = true;
} else {
this._blobContainerButton.checked = false;
this._blobTableContainer.display = 'none';
await this._blobContainer.updateCssStyles({ 'display': 'none' });
}
}
if (!(this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
await this._targetDatabaseContainer.updateCssStyles({ 'display': 'none' });
await this._networkShareStorageAccountDetails.updateCssStyles({ 'display': 'none' });
}
const connectionProfile = await this.migrationStateModel.getSourceConnectionProfile();
const queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>((await this.migrationStateModel.getSourceConnectionProfile()).providerId, azdata.DataProviderType.QueryProvider);
const query = 'select SUSER_NAME()';
@@ -788,6 +764,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this._sourceHelpText.value = constants.SQL_SOURCE_DETAILS(this.migrationStateModel._authenticationType, connectionProfile.serverName);
this._sqlSourceUsernameInput.value = username;
this._sqlSourcePassword.value = (await azdata.connection.getCredentials(this.migrationStateModel.sourceConnectionId)).password;
this._windowsUserAccountText.value = this.migrationStateModel.savedInfo?.networkShares[0]?.windowsUser;
this._networkShareTargetDatabaseNames = [];
this._networkShareLocations = [];
@@ -800,16 +777,45 @@ export class DatabaseBackupPage extends MigrationWizardPage {
if (this.migrationStateModel._targetType === MigrationTargetType.SQLMI) {
this._existingDatabases = await this.migrationStateModel.getManagedDatabases();
}
this.migrationStateModel._targetDatabaseNames = [];
this.migrationStateModel._databaseBackup.blobs = [];
this.migrationStateModel._databaseBackup.networkShares = [];
this.migrationStateModel._migrationDbs.forEach((db, index) => {
this.migrationStateModel._targetDatabaseNames.push(db);
this.migrationStateModel._databaseBackup.blobs.push(<Blob>{});
this.migrationStateModel._databaseBackup.networkShares.push(<NetworkShare>{});
let originalTargetDatabaseNames = this.migrationStateModel._targetDatabaseNames;
let originalNetworkShares = this.migrationStateModel._databaseBackup.networkShares;
let originalBlobs = this.migrationStateModel._databaseBackup.blobs;
if (this.migrationStateModel._didUpdateDatabasesForMigration) {
this.migrationStateModel._targetDatabaseNames = [];
this.migrationStateModel._databaseBackup.networkShares = [];
this.migrationStateModel._databaseBackup.blobs = [];
}
this.migrationStateModel._databasesForMigration.forEach((db, index) => {
let targetDatabaseName = db;
let networkShare = <NetworkShare>{};
let blob = <Blob>{};
if (this.migrationStateModel._didUpdateDatabasesForMigration) {
const dbIndex = this.migrationStateModel._sourceDatabaseNames?.indexOf(db);
if (dbIndex > -1) {
targetDatabaseName = originalTargetDatabaseNames[dbIndex] ?? targetDatabaseName;
networkShare = originalNetworkShares[dbIndex] ?? networkShare;
blob = originalBlobs[dbIndex] ?? blob;
} else {
// network share values are uniform for all dbs in the same migration, except for networkShareLocation
const previouslySelectedNetworkShare = originalNetworkShares[0];
if (previouslySelectedNetworkShare) {
networkShare = {
...previouslySelectedNetworkShare,
networkShareLocation: '',
};
}
}
}
this.migrationStateModel._targetDatabaseNames[index] = targetDatabaseName;
this.migrationStateModel._databaseBackup.networkShares[index] = networkShare;
this.migrationStateModel._databaseBackup.blobs[index] = blob;
const targetDatabaseInput = this._view.modelBuilder.inputBox().withProps({
required: true,
value: db,
value: targetDatabaseName,
width: WIZARD_TABLE_COLUMN_WIDTH
}).withValidation(c => {
if (this._networkShareTargetDatabaseNames.filter(t => t.value === c.value).length > 1) { //Making sure no databases have duplicate values.
@@ -830,11 +836,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this.migrationStateModel._targetDatabaseNames[index] = value.trim();
await this.validateFields();
}));
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
targetDatabaseInput.value = this.migrationStateModel.savedInfo.targetDatabaseNames[index];
} else {
targetDatabaseInput.value = this.migrationStateModel._targetDatabaseNames[index];
}
targetDatabaseInput.value = this.migrationStateModel._targetDatabaseNames[index];
this._networkShareTargetDatabaseNames.push(targetDatabaseInput);
const networkShareLocationInput = this._view.modelBuilder.inputBox().withProps({
@@ -856,16 +858,12 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this.migrationStateModel._databaseBackup.networkShares[index].networkShareLocation = value.trim();
await this.validateFields();
}));
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
networkShareLocationInput.value = this.migrationStateModel.savedInfo.networkShares[index].networkShareLocation;
} else {
networkShareLocationInput.value = this.migrationStateModel._databaseBackup.networkShares[index]?.networkShareLocation;
}
networkShareLocationInput.value = this.migrationStateModel._databaseBackup.networkShares[index]?.networkShareLocation;
this._networkShareLocations.push(networkShareLocationInput);
const blobTargetDatabaseInput = this._view.modelBuilder.inputBox().withProps({
required: true,
value: db,
value: targetDatabaseName,
}).withValidation(c => {
if (this._blobContainerTargetDatabaseNames.filter(t => t.value === c.value).length > 1) { //Making sure no databases have duplicate values.
c.validationErrorMessage = constants.DUPLICATE_NAME_ERROR;
@@ -884,11 +882,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this._disposables.push(blobTargetDatabaseInput.onTextChanged((value) => {
this.migrationStateModel._targetDatabaseNames[index] = value.trim();
}));
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
blobTargetDatabaseInput.value = this.migrationStateModel.savedInfo.targetDatabaseNames[index];
} else {
targetDatabaseInput.value = this.migrationStateModel._targetDatabaseNames[index];
}
targetDatabaseInput.value = this.migrationStateModel._targetDatabaseNames[index];
this._blobContainerTargetDatabaseNames.push(blobTargetDatabaseInput);
const blobContainerResourceDropdown = this._view.modelBuilder.dropDown().withProps({
@@ -970,10 +964,11 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this._blobContainerLastBackupFileDropdowns.push(blobContainerLastBackupFileDropdown);
}
});
this.migrationStateModel._sourceDatabaseNames = this.migrationStateModel._databasesForMigration;
let data: azdata.DeclarativeTableCellValue[][] = [];
this.migrationStateModel._migrationDbs.forEach((db, index) => {
this.migrationStateModel._databasesForMigration.forEach((db, index) => {
const targetRow: azdata.DeclarativeTableCellValue[] = [];
targetRow.push({
value: db
@@ -989,7 +984,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
await this._networkShareTargetDatabaseNamesTable.setDataValues(data);
data = [];
this.migrationStateModel._migrationDbs.forEach((db, index) => {
this.migrationStateModel._databasesForMigration.forEach((db, index) => {
const targetRow: azdata.DeclarativeTableCellValue[] = [];
targetRow.push({
value: db
@@ -1037,7 +1032,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
const errors: string[] = [];
switch (this.migrationStateModel._databaseBackup.networkContainerType) {
case NetworkContainerType.NETWORK_SHARE:
case NetworkContainerType.NETWORK_SHARE: {
if ((<azdata.CategoryValue>this._networkShareStorageAccountResourceGroupDropdown.value)?.displayName === constants.RESOURCE_GROUP_NOT_FOUND) {
errors.push(constants.INVALID_RESOURCE_GROUP_ERROR);
}
@@ -1045,27 +1040,29 @@ export class DatabaseBackupPage extends MigrationWizardPage {
errors.push(constants.INVALID_STORAGE_ACCOUNT_ERROR);
}
break;
case NetworkContainerType.BLOB_CONTAINER:
}
case NetworkContainerType.BLOB_CONTAINER: {
this._blobContainerResourceGroupDropdowns.forEach((v, index) => {
if (this.shouldDisplayBlobDropdownError(v, [constants.RESOURCE_GROUP_NOT_FOUND])) {
errors.push(constants.INVALID_BLOB_RESOURCE_GROUP_ERROR(this.migrationStateModel._migrationDbs[index]));
errors.push(constants.INVALID_BLOB_RESOURCE_GROUP_ERROR(this.migrationStateModel._databasesForMigration[index]));
}
});
this._blobContainerStorageAccountDropdowns.forEach((v, index) => {
if (this.shouldDisplayBlobDropdownError(v, [constants.NO_STORAGE_ACCOUNT_FOUND, constants.SELECT_RESOURCE_GROUP_PROMPT])) {
errors.push(constants.INVALID_BLOB_STORAGE_ACCOUNT_ERROR(this.migrationStateModel._migrationDbs[index]));
errors.push(constants.INVALID_BLOB_STORAGE_ACCOUNT_ERROR(this.migrationStateModel._databasesForMigration[index]));
}
});
this._blobContainerDropdowns.forEach((v, index) => {
if (this.shouldDisplayBlobDropdownError(v, [constants.NO_BLOBCONTAINERS_FOUND, constants.SELECT_STORAGE_ACCOUNT])) {
errors.push(constants.INVALID_BLOB_CONTAINER_ERROR(this.migrationStateModel._migrationDbs[index]));
errors.push(constants.INVALID_BLOB_CONTAINER_ERROR(this.migrationStateModel._databasesForMigration[index]));
}
});
if (this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE) {
this._blobContainerLastBackupFileDropdowns.forEach((v, index) => {
if (this.shouldDisplayBlobDropdownError(v, [constants.NO_BLOBFILES_FOUND, constants.SELECT_BLOB_CONTAINER])) {
errors.push(constants.INVALID_BLOB_LAST_BACKUP_FILE_ERROR(this.migrationStateModel._migrationDbs[index]));
errors.push(constants.INVALID_BLOB_LAST_BACKUP_FILE_ERROR(this.migrationStateModel._databasesForMigration[index]));
}
});
}
@@ -1082,13 +1079,16 @@ export class DatabaseBackupPage extends MigrationWizardPage {
}
duplicates.forEach((d) => {
if (d.length > 1) {
const dupString = `${d.map(index => this.migrationStateModel._migrationDbs[index]).join(', ')}`;
const dupString = `${d.map(index => this.migrationStateModel._databasesForMigration[index]).join(', ')}`;
errors.push(constants.PROVIDE_UNIQUE_CONTAINERS + dupString);
}
});
}
break;
}
default:
return false;
}
this.migrationStateModel._targetDatabaseNames.forEach(t => {
@@ -1123,7 +1123,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
break;
case NetworkContainerType.NETWORK_SHARE:
// All network share migrations use the same storage account
const storageAccount = this.migrationStateModel._databaseBackup.networkShares[0].storageAccount;
const storageAccount = this.migrationStateModel._databaseBackup.networkShares[0]?.storageAccount;
const storageKey = (await getStorageAccountAccessKeys(
this.migrationStateModel._azureAccount,
this.migrationStateModel._databaseBackup.subscription,
@@ -1152,16 +1152,29 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this.wizard.nextButton.enabled = true;
this.migrationStateModel._databaseBackup.networkContainerType = containerType;
await this._blobContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.BLOB_CONTAINER) ? 'inline' : 'none' });
await this._networkShareContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none' });
await this._networkShareStorageAccountDetails.updateCssStyles({ 'display': (containerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none' });
await this._targetDatabaseContainer.updateCssStyles({ 'display': 'inline' });
this._networkTableContainer.display = (containerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none';
this._blobTableContainer.display = (containerType === NetworkContainerType.BLOB_CONTAINER) ? 'inline' : 'none';
//Preserving the database Names between the 2 tables.
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
this.migrationStateModel._targetDatabaseNames = this.migrationStateModel.savedInfo.targetDatabaseNames;
switch (containerType) {
case NetworkContainerType.NETWORK_SHARE: {
await this._networkShareContainer.updateCssStyles({ 'display': 'inline' });
await this._networkShareStorageAccountDetails.updateCssStyles({ 'display': 'inline' });
await this._networkTableContainer.updateCssStyles({ 'display': 'inline' });
await this._blobContainer.updateCssStyles({ 'display': 'none' });
await this._blobTableContainer.updateCssStyles({ 'display': 'none' });
break;
}
case NetworkContainerType.BLOB_CONTAINER: {
await this._networkShareContainer.updateCssStyles({ 'display': 'none' });
await this._networkShareStorageAccountDetails.updateCssStyles({ 'display': 'none' });
await this._networkTableContainer.updateCssStyles({ 'display': 'none' });
await this._blobContainer.updateCssStyles({ 'display': 'inline' });
await this._blobTableContainer.updateCssStyles({ 'display': 'inline' });
break;
}
}
await this._windowsUserAccountText.updateProperties({
@@ -1203,11 +1216,6 @@ export class DatabaseBackupPage extends MigrationWizardPage {
}
private async getSubscriptionValues(): Promise<void> {
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
this.migrationStateModel._targetSubscription = <azureResource.AzureResourceSubscription>this.migrationStateModel.savedInfo.targetSubscription;
this.migrationStateModel._targetServerInstance = <SqlManagedInstance | SqlVMServer>this.migrationStateModel.savedInfo.targetServerInstance;
}
this._networkShareContainerSubscription.value = this.migrationStateModel._targetSubscription.name;
this._networkShareContainerLocation.value = await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.location);
@@ -1224,15 +1232,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this._networkShareStorageAccountResourceGroupDropdown.loading = true;
try {
this._networkShareStorageAccountResourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._databaseBackup.subscription);
if (this.hasSavedInfo(NetworkContainerType.NETWORK_SHARE, this._networkShareStorageAccountResourceGroupDropdown.values)) {
this._networkShareStorageAccountResourceGroupDropdown.values.forEach((resource, index) => {
if ((<azdata.CategoryValue>resource).name.toLowerCase() === this.migrationStateModel.savedInfo?.networkShares[0].resourceGroup?.id?.toLowerCase()) {
selectDropDownIndex(this._networkShareStorageAccountResourceGroupDropdown, index);
}
});
} else {
selectDropDownIndex(this._networkShareStorageAccountResourceGroupDropdown, 0);
}
selectDefaultDropdownValue(this._networkShareStorageAccountResourceGroupDropdown, this.migrationStateModel._databaseBackup?.networkShares[0]?.resourceGroup?.id, false);
} catch (error) {
logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingNetworkStorageResourceGroup', error);
} finally {
@@ -1243,13 +1243,15 @@ export class DatabaseBackupPage extends MigrationWizardPage {
private async loadNetworkShareStorageDropdown(): Promise<void> {
this._networkShareContainerStorageAccountDropdown.loading = true;
this._networkShareStorageAccountResourceGroupDropdown.loading = true;
try {
this._networkShareContainerStorageAccountDropdown.values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel._databaseBackup.subscription, this.migrationStateModel._databaseBackup.networkShares[0].resourceGroup);
selectDropDownIndex(this._networkShareContainerStorageAccountDropdown, 0);
this._networkShareContainerStorageAccountDropdown.values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel._databaseBackup.subscription, this.migrationStateModel._databaseBackup.networkShares[0]?.resourceGroup);
selectDefaultDropdownValue(this._networkShareContainerStorageAccountDropdown, this.migrationStateModel?._databaseBackup?.networkShares[0]?.storageAccount?.id, false);
} catch (error) {
logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingNetworkShareStorageDropdown', error);
} finally {
this._networkShareContainerStorageAccountDropdown.loading = false;
this._networkShareStorageAccountResourceGroupDropdown.loading = false;
}
}
@@ -1259,15 +1261,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
const resourceGroupValues = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._databaseBackup.subscription);
this._blobContainerResourceGroupDropdowns.forEach((dropDown, index) => {
dropDown.values = resourceGroupValues;
if (this.hasSavedInfo(NetworkContainerType.BLOB_CONTAINER, dropDown.values)) {
dropDown.values.forEach((resource, resourceIndex) => {
if ((<azdata.CategoryValue>resource).name.toLowerCase() === this.migrationStateModel.savedInfo?.blobs[index]?.resourceGroup?.id?.toLowerCase()) {
selectDropDownIndex(dropDown, resourceIndex);
}
});
} else {
selectDropDownIndex(dropDown, 0);
}
selectDefaultDropdownValue(dropDown, this.migrationStateModel._databaseBackup?.blobs[index]?.resourceGroup?.id, false);
});
} catch (error) {
logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingBlobResourceGroup', error);
@@ -1280,15 +1274,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this._blobContainerStorageAccountDropdowns[index].loading = true;
try {
this._blobContainerStorageAccountDropdowns[index].values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel._databaseBackup.subscription, this.migrationStateModel._databaseBackup.blobs[index]?.resourceGroup);
if (this.hasSavedInfo(NetworkContainerType.BLOB_CONTAINER, this._blobContainerStorageAccountDropdowns[index].values && this.migrationStateModel.savedInfo.blobs[index]?.storageAccount)) {
this._blobContainerStorageAccountDropdowns[index].values!.forEach((resource, resourceIndex) => {
if ((<azdata.CategoryValue>resource).name.toLowerCase() === this.migrationStateModel.savedInfo?.blobs[index]?.storageAccount?.id?.toLowerCase()) {
selectDropDownIndex(this._blobContainerStorageAccountDropdowns[index], resourceIndex);
}
});
} else {
selectDropDownIndex(this._blobContainerStorageAccountDropdowns[index], 0);
}
selectDefaultDropdownValue(this._blobContainerStorageAccountDropdowns[index], this.migrationStateModel._databaseBackup?.blobs[index]?.storageAccount?.id, false);
} catch (error) {
logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingBlobStorageDropdown', error);
} finally {
@@ -1301,15 +1287,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
try {
const blobContainerValues = await this.migrationStateModel.getBlobContainerValues(this.migrationStateModel._databaseBackup.subscription, this.migrationStateModel._databaseBackup.blobs[index]?.storageAccount);
this._blobContainerDropdowns[index].values = blobContainerValues;
if (this.hasSavedInfo(NetworkContainerType.BLOB_CONTAINER, this._blobContainerDropdowns[index].values && this.migrationStateModel.savedInfo.blobs[index]?.blobContainer)) {
this._blobContainerDropdowns[index].values!.forEach((resource, resourceIndex) => {
if ((<azdata.CategoryValue>resource).name.toLowerCase() === this.migrationStateModel.savedInfo?.blobs[index]?.blobContainer?.id?.toLowerCase()) {
selectDropDownIndex(this._blobContainerDropdowns[index], resourceIndex);
}
});
} else {
selectDropDownIndex(this._blobContainerDropdowns[index], 0);
}
selectDefaultDropdownValue(this._blobContainerDropdowns[index], this.migrationStateModel._databaseBackup?.blobs[index]?.blobContainer?.id, false);
} catch (error) {
logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingBlobContainers', error);
} finally {
@@ -1322,15 +1300,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
try {
const blobLastBackupFileValues = await this.migrationStateModel.getBlobLastBackupFileNameValues(this.migrationStateModel._databaseBackup.subscription, this.migrationStateModel._databaseBackup.blobs[index]?.storageAccount, this.migrationStateModel._databaseBackup.blobs[index]?.blobContainer);
this._blobContainerLastBackupFileDropdowns[index].values = blobLastBackupFileValues;
if (this.hasSavedInfo(NetworkContainerType.BLOB_CONTAINER, this._blobContainerLastBackupFileDropdowns[index].values && this.migrationStateModel.savedInfo.blobs[index]?.lastBackupFile)) {
this._blobContainerLastBackupFileDropdowns[index].values!.forEach((resource, resourceIndex) => {
if ((<azdata.CategoryValue>resource).name.toLowerCase() === this.migrationStateModel.savedInfo?.blobs[index]?.lastBackupFile!.toLowerCase()) {
selectDropDownIndex(this._blobContainerLastBackupFileDropdowns[index], resourceIndex);
}
});
} else {
selectDropDownIndex(this._blobContainerLastBackupFileDropdowns[index], 0);
}
selectDefaultDropdownValue(this._blobContainerLastBackupFileDropdowns[index], this.migrationStateModel._databaseBackup?.blobs[index]?.lastBackupFile, false);
} catch (error) {
logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingBlobLastBackupFiles', error);
} finally {
@@ -1362,12 +1332,4 @@ export class DatabaseBackupPage extends MigrationWizardPage {
selectDropDownIndex(this._blobContainerStorageAccountDropdowns[rowIndex], 0);
await this._blobContainerStorageAccountDropdowns[rowIndex].updateProperties(dropdownProps);
}
private hasSavedInfo(networkContainerType: NetworkContainerType, values: any): boolean {
if (this.migrationStateModel._databaseBackup.networkContainerType === networkContainerType &&
(this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup) && values)) {
return true;
}
return false;
}
}

View File

@@ -6,11 +6,12 @@
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { MigrationWizardPage } from '../models/migrationWizardPage';
import { MigrationStateModel, Page, StateChangeEvent } from '../models/stateMachine';
import { MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
import * as constants from '../constants/strings';
import { IconPath, IconPathHelper } from '../constants/iconPathHelper';
import { debounce } from '../api/utils';
import * as styles from '../constants/styles';
import { selectDatabasesFromList } from '../constants/helper';
const styleLeft: azdata.CssStyles = {
'border': 'none',
@@ -89,12 +90,14 @@ export class DatabaseSelectorPage extends MigrationWizardPage {
}
public async onPageLeave(): Promise<void> {
const assessedDatabases = this.migrationStateModel._databaseAssessment ?? [];
const selectedDatabases = this.selectedDbs();
const assessedDatabases = this.migrationStateModel._assessedDatabaseList ?? [];
const selectedDatabases = this.migrationStateModel._databasesForAssessment;
// run assessment if
// * no prior assessment
// * the prior assessment had an error or
// * the assessed databases list is different from the selected databases list
this.migrationStateModel._runAssessments = !!this.migrationStateModel._assessmentResults?.assessmentError
this.migrationStateModel._runAssessments = !this.migrationStateModel._assessmentResults
|| !!this.migrationStateModel._assessmentResults?.assessmentError
|| assessedDatabases.length === 0
|| assessedDatabases.length !== selectedDatabases.length
|| assessedDatabases.some(db => selectedDatabases.indexOf(db) < 0);
@@ -268,20 +271,8 @@ export class DatabaseSelectorPage extends MigrationWizardPage {
}
).component();
if (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseSelector) {
await this._databaseSelectorTable.setDataValues(this.migrationStateModel.savedInfo.selectedDatabases);
} else {
if (this.migrationStateModel.retryMigration) {
const sourceDatabaseName = this.migrationStateModel.savedInfo.databaseList[0];
this._databaseTableValues.forEach((row, index) => {
const dbName = row[1].value as string;
if (dbName?.toLowerCase() === sourceDatabaseName?.toLowerCase()) {
row[0].value = true;
}
});
}
await this._databaseSelectorTable.setDataValues(this._databaseTableValues);
}
this._databaseTableValues = selectDatabasesFromList(this.migrationStateModel._databasesForAssessment, this._databaseTableValues);
await this._databaseSelectorTable.setDataValues(this._databaseTableValues);
await this.updateValuesOnSelection();
this._disposables.push(this._databaseSelectorTable.onDataChanged(async () => {
@@ -300,7 +291,6 @@ export class DatabaseSelectorPage extends MigrationWizardPage {
flex.addItem(this._dbCount, { flex: '0 0 auto' });
flex.addItem(this._databaseSelectorTable);
return flex;
// insert names of databases into table
}
public selectedDbs(): string[] {
@@ -317,8 +307,7 @@ export class DatabaseSelectorPage extends MigrationWizardPage {
await this._dbCount.updateProperties({
'value': constants.DATABASES_SELECTED(this.selectedDbs().length, this._databaseTableValues.length)
});
this.migrationStateModel._databaseAssessment = this.selectedDbs();
this.migrationStateModel.databaseSelectorTableValues = <azdata.DeclarativeTableCellValue[][]>this._databaseSelectorTable.dataValues;
this.migrationStateModel._databasesForAssessment = this.selectedDbs();
}
// undo when bug #16445 is fixed

View File

@@ -5,16 +5,15 @@
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { azureResource } from 'azureResource';
import { MigrationWizardPage } from '../models/migrationWizardPage';
import { MigrationStateModel, NetworkContainerType, Page, StateChangeEvent } from '../models/stateMachine';
import { MigrationStateModel, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
import { CreateSqlMigrationServiceDialog } from '../dialog/createSqlMigrationService/createSqlMigrationServiceDialog';
import * as constants from '../constants/strings';
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
import { getFullResourceGroupFromId, getLocationDisplayName, getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlManagedInstance, SqlVMServer } from '../api/azure';
import { getFullResourceGroupFromId, getLocationDisplayName, getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData } from '../api/azure';
import { IconPathHelper } from '../constants/iconPathHelper';
import { logError, TelemetryViews } from '../telemtery';
import { findDropDownItemIndex, selectDropDownIndex } from '../api/utils';
import { findDropDownItemIndex, selectDefaultDropdownValue } from '../api/utils';
import * as styles from '../constants/styles';
export class IntergrationRuntimePage extends MigrationWizardPage {
@@ -76,11 +75,6 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
}
public async onPageEnter(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.IntegrationRuntime)) {
this.migrationStateModel._targetSubscription = <azureResource.AzureResourceSubscription>this.migrationStateModel.savedInfo.targetSubscription;
this.migrationStateModel._targetServerInstance = <SqlManagedInstance | SqlVMServer>this.migrationStateModel.savedInfo.targetServerInstance;
}
this._subscription.value = this.migrationStateModel._targetSubscription.name;
this._location.value = await getLocationDisplayName(this.migrationStateModel._targetServerInstance.location);
this._dmsInfoContainer.display = (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE && this.migrationStateModel._sqlMigrationService) ? 'inline' : 'none';
@@ -183,10 +177,13 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
}).component();
this._disposables.push(this._resourceGroupDropdown.onValueChanged(async (value) => {
const selectedIndex = findDropDownItemIndex(this._resourceGroupDropdown, value);
this.migrationStateModel._sqlMigrationServiceResourceGroup = this.migrationStateModel.getAzureResourceGroup(selectedIndex).name;
if (selectedIndex > -1) {
await this.populateDms(value);
if (selectedIndex > -1 &&
value !== constants.RESOURCE_GROUP_NOT_FOUND) {
this.migrationStateModel._sqlMigrationServiceResourceGroup = this.migrationStateModel.getAzureResourceGroup(selectedIndex).name;
} else {
this.migrationStateModel._sqlMigrationServiceResourceGroup = undefined!;
}
await this.populateDms();
}));
const migrationServiceDropdownLabel = this._view.modelBuilder.text().withProps({
@@ -216,8 +213,10 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
text: ''
};
const selectedIndex = findDropDownItemIndex(this._dmsDropdown, value);
this.migrationStateModel._sqlMigrationService = this.migrationStateModel.getMigrationService(selectedIndex);
await this.loadMigrationServiceStatus();
if (selectedIndex > -1) {
this.migrationStateModel._sqlMigrationService = this.migrationStateModel.getMigrationService(selectedIndex);
await this.loadMigrationServiceStatus();
}
} else {
this.migrationStateModel._sqlMigrationService = undefined;
this._dmsInfoContainer.display = 'none';
@@ -238,7 +237,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
this.migrationStateModel._sqlMigrationServiceResourceGroup = createdDmsResult.resourceGroup;
this.migrationStateModel._sqlMigrationService = createdDmsResult.service;
await this.loadResourceGroupDropdown();
await this.populateDms(createdDmsResult.resourceGroup);
await this.populateDms();
}));
const flexContainer = this._view.modelBuilder.flexContainer().withItems([
@@ -376,38 +375,26 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
return container;
}
public async loadResourceGroupDropdown(): Promise<void> {
this._resourceGroupDropdown.loading = true;
this._dmsDropdown.loading = true;
try {
this._resourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._targetSubscription);
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.IntegrationRuntime && this._resourceGroupDropdown.values)) {
this._resourceGroupDropdown.values.forEach((resource, resourceIndex) => {
const resourceId = this.migrationStateModel.savedInfo?.migrationServiceId?.toLowerCase();
if (resourceId && (<azdata.CategoryValue>resource).name.toLowerCase() === getFullResourceGroupFromId(resourceId)) {
selectDropDownIndex(this._resourceGroupDropdown, resourceIndex);
}
});
}
const resourceGroup = (this.migrationStateModel._sqlMigrationService)
? getFullResourceGroupFromId(this.migrationStateModel._sqlMigrationService?.id)
: undefined;
selectDefaultDropdownValue(this._resourceGroupDropdown, resourceGroup, false);
} finally {
this._resourceGroupDropdown.loading = false;
this._dmsDropdown.loading = false;
}
}
public async populateDms(resourceGroupName: string): Promise<void> {
public async populateDms(): Promise<void> {
this._dmsDropdown.loading = true;
try {
this._dmsDropdown.values = await this.migrationStateModel.getSqlMigrationServiceValues(this.migrationStateModel._targetSubscription, <SqlManagedInstance>this.migrationStateModel._targetServerInstance, resourceGroupName);
const selectedSqlMigrationService = this._dmsDropdown.values.find(v => v.displayName.toLowerCase() === this.migrationStateModel._sqlMigrationService?.name?.toLowerCase());
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.IntegrationRuntime && this._dmsDropdown.values)) {
this._dmsDropdown.values.forEach((resource, resourceIndex) => {
if ((<azdata.CategoryValue>resource).name.toLowerCase() === this.migrationStateModel.savedInfo?.migrationServiceId?.toLowerCase()) {
selectDropDownIndex(this._dmsDropdown, resourceIndex);
}
});
} else {
this._dmsDropdown.value = (selectedSqlMigrationService) ? selectedSqlMigrationService : this._dmsDropdown.values[0];
}
this._dmsDropdown.values = await this.migrationStateModel.getSqlMigrationServiceValues(this.migrationStateModel._targetSubscription, this.migrationStateModel._sqlMigrationServiceResourceGroup);
selectDefaultDropdownValue(this._dmsDropdown, this.migrationStateModel._sqlMigrationService?.id, false);
} finally {
this._dmsDropdown.loading = false;
}

View File

@@ -6,7 +6,7 @@
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { MigrationWizardPage } from '../models/migrationWizardPage';
import { MigrationMode, MigrationStateModel, Page, StateChangeEvent } from '../models/stateMachine';
import { MigrationMode, MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
import * as constants from '../constants/strings';
import * as styles from '../constants/styles';
@@ -17,6 +17,7 @@ export class MigrationModePage extends MigrationWizardPage {
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
super(wizard, azdata.window.createWizardPage(constants.DATABASE_BACKUP_MIGRATION_MODE_LABEL, 'MigrationModePage'), migrationStateModel);
this.migrationStateModel._databaseBackup.migrationMode = this.migrationStateModel._databaseBackup.migrationMode || MigrationMode.ONLINE;
}
protected async registerContent(view: azdata.ModelView): Promise<void> {
@@ -59,7 +60,7 @@ export class MigrationModePage extends MigrationWizardPage {
});
}
public async onPageLeave(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
if (this.originalMigrationMode !== this.migrationStateModel._databaseBackup.migrationMode || this.migrationStateModel.resumeAssessment) {
if (this.originalMigrationMode !== this.migrationStateModel._databaseBackup.migrationMode) {
this.migrationStateModel.refreshDatabaseBackupPage = true;
}
@@ -71,15 +72,15 @@ export class MigrationModePage extends MigrationWizardPage {
}
private migrationModeContainer(): azdata.FormComponent {
const buttonGroup = 'cutoverContainer';
const buttonGroup = 'migrationMode';
const onlineButton = this._view.modelBuilder.radioButton().withProps({
label: constants.DATABASE_BACKUP_MIGRATION_MODE_ONLINE_LABEL,
name: buttonGroup,
checked: this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.ONLINE,
CSSStyles: {
...styles.LABEL_CSS,
},
checked: true
}).component();
const onlineDescription = this._view.modelBuilder.text().withProps({
@@ -99,6 +100,7 @@ export class MigrationModePage extends MigrationWizardPage {
const offlineButton = this._view.modelBuilder.radioButton().withProps({
label: constants.DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_LABEL,
name: buttonGroup,
checked: this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE,
CSSStyles: {
...styles.LABEL_CSS,
'margin-top': '12px'
@@ -113,16 +115,6 @@ export class MigrationModePage extends MigrationWizardPage {
}
}).component();
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.MigrationMode)) {
if (this.migrationStateModel.savedInfo.migrationMode === MigrationMode.ONLINE) {
onlineButton.checked = true;
offlineButton.checked = false;
} else {
onlineButton.checked = false;
offlineButton.checked = true;
}
}
this._disposables.push(offlineButton.onDidChangeCheckedState((e) => {
if (e) {
this.migrationStateModel._databaseBackup.migrationMode = MigrationMode.OFFLINE;

View File

@@ -7,7 +7,7 @@ import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as mssql from '../../../mssql';
import { MigrationWizardPage } from '../models/migrationWizardPage';
import { MigrationStateModel, MigrationTargetType, Page, PerformanceDataSourceOptions, ServerAssessment, StateChangeEvent } from '../models/stateMachine';
import { MigrationStateModel, MigrationTargetType, PerformanceDataSourceOptions, StateChangeEvent } from '../models/stateMachine';
import { AssessmentResultsDialog } from '../dialog/assessmentResults/assessmentResultsDialog';
import { SkuRecommendationResultsDialog } from '../dialog/skuRecommendationResults/skuRecommendationResultsDialog';
import { GetAzureRecommendationDialog } from '../dialog/skuRecommendationResults/getAzureRecommendationDialog';
@@ -17,6 +17,7 @@ import { IconPath, IconPathHelper } from '../constants/iconPathHelper';
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
import * as styles from '../constants/styles';
import { SkuEditParametersDialog } from '../dialog/skuRecommendationResults/skuEditParametersDialog';
import { logError, TelemetryViews } from '../telemtery';
export interface Product {
type: MigrationTargetType;
@@ -153,7 +154,7 @@ export class SKURecommendationPage extends MigrationWizardPage {
this._disposables.push(refreshAssessmentButton.onDidClick(async () => {
await this.startCardLoading();
await this.migrationStateModel.getSkuRecommendations();
this.migrationStateModel._runAssessments = true;
await this.constructDetails();
}));
@@ -382,12 +383,7 @@ export class SKURecommendationPage extends MigrationWizardPage {
}
}).component();
let serverName = '';
if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.serverName)) {
serverName = this.migrationStateModel.serverName;
} else {
serverName = (await this.migrationStateModel.getSourceConnectionProfile()).serverName;
}
let serverName = this.migrationStateModel.serverName || (await this.migrationStateModel.getSourceConnectionProfile()).serverName;
let miDialog = new AssessmentResultsDialog('ownerUri', this.migrationStateModel, constants.ASSESSMENT_TILE(serverName), this, MigrationTargetType.SQLMI);
let vmDialog = new AssessmentResultsDialog('ownerUri', this.migrationStateModel, constants.ASSESSMENT_TILE(serverName), this, MigrationTargetType.SQLVM);
@@ -419,37 +415,31 @@ export class SKURecommendationPage extends MigrationWizardPage {
}
private async changeTargetType(newTargetType: string) {
if (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.SKURecommendation) {
this.migrationStateModel._databaseAssessment = <string[]>this.migrationStateModel.savedInfo.databaseAssessment;
}
// remove assessed databases that have been removed from the source selection list
const miDbs = this.migrationStateModel._miDbs.filter(
db => this.migrationStateModel._databaseAssessment.findIndex(
dba => dba === db) >= 0);
switch (newTargetType) {
case MigrationTargetType.SQLMI: {
const miDbs = this.migrationStateModel._miDbs.filter(
db => this.migrationStateModel._databasesForAssessment.findIndex(
dba => dba === db) >= 0);
const vmDbs = this.migrationStateModel._vmDbs.filter(
db => this.migrationStateModel._databaseAssessment.findIndex(
dba => dba === db) >= 0);
this._viewAssessmentsHelperText.value = constants.SKU_RECOMMENDATION_VIEW_ASSESSMENT_MI;
this.migrationStateModel._targetType = MigrationTargetType.SQLMI;
this.migrationStateModel._databasesForMigration = miDbs;
break;
}
if (newTargetType === MigrationTargetType.SQLMI) {
this._viewAssessmentsHelperText.value = constants.SKU_RECOMMENDATION_VIEW_ASSESSMENT_MI;
if (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.SKURecommendation) {
this._databaseSelectedHelperText.value = constants.TOTAL_DATABASES_SELECTED(this.migrationStateModel.savedInfo.databaseList.length, this.migrationStateModel._databaseAssessment.length);
} else {
this._databaseSelectedHelperText.value = constants.TOTAL_DATABASES_SELECTED(miDbs.length, this.migrationStateModel._databaseAssessment.length);
case MigrationTargetType.SQLVM: {
const vmDbs = this.migrationStateModel._vmDbs.filter(
db => this.migrationStateModel._databasesForAssessment.findIndex(
dba => dba === db) >= 0);
this._viewAssessmentsHelperText.value = constants.SKU_RECOMMENDATION_VIEW_ASSESSMENT_VM;
this.migrationStateModel._targetType = MigrationTargetType.SQLVM;
this.migrationStateModel._databasesForMigration = vmDbs;
break;
}
this.migrationStateModel._targetType = MigrationTargetType.SQLMI;
this.migrationStateModel._migrationDbs = miDbs;
} else {
this._viewAssessmentsHelperText.value = constants.SKU_RECOMMENDATION_VIEW_ASSESSMENT_VM;
if ((this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.SKURecommendation)) {
this._databaseSelectedHelperText.value = constants.TOTAL_DATABASES_SELECTED(this.migrationStateModel.savedInfo.databaseList.length, this.migrationStateModel._databaseAssessment.length);
} else {
this._databaseSelectedHelperText.value = constants.TOTAL_DATABASES_SELECTED(vmDbs.length, this.migrationStateModel._databaseAssessment.length);
}
this.migrationStateModel._targetType = MigrationTargetType.SQLVM;
this.migrationStateModel._migrationDbs = vmDbs;
}
this._databaseSelectedHelperText.value = constants.TOTAL_DATABASES_SELECTED(this.migrationStateModel._databasesForMigration.length, this.migrationStateModel._databasesForAssessment.length);
this.migrationStateModel.refreshDatabaseBackupPage = true;
}
@@ -459,100 +449,89 @@ export class SKURecommendationPage extends MigrationWizardPage {
level: azdata.window.MessageLevel.Error
};
await this._setAssessmentState(true, false);
const serverName = (await this.migrationStateModel.getSourceConnectionProfile()).serverName;
const errors: string[] = [];
try {
if (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage) {
this.migrationStateModel._assessmentResults = <ServerAssessment>this.migrationStateModel.savedInfo.serverAssessment;
} else {
if (this.migrationStateModel._runAssessments) {
const errors: string[] = [];
await this._setAssessmentState(true, false);
try {
await this.migrationStateModel.getDatabaseAssessments(MigrationTargetType.SQLMI);
}
const assessmentError = this.migrationStateModel._assessmentResults?.assessmentError;
if (assessmentError) {
errors.push(`message: ${assessmentError.message}${EOL}stack: ${assessmentError.stack}`);
}
if (this.migrationStateModel?._assessmentResults?.errors?.length! > 0) {
errors.push(...this.migrationStateModel._assessmentResults?.errors?.map(
e => `message: ${e.message}${EOL}errorSummary: ${e.errorSummary}${EOL}possibleCauses: ${e.possibleCauses}${EOL}guidance: ${e.guidance}${EOL}errorId: ${e.errorId}`)!);
}
} catch (e) {
console.log(e);
errors.push(constants.SKU_RECOMMENDATION_ASSESSMENT_UNEXPECTED_ERROR(serverName, e));
} finally {
this.migrationStateModel._runAssessments = errors.length > 0;
if (errors.length > 0) {
this.wizard.message = {
text: constants.SKU_RECOMMENDATION_ASSESSMENT_ERROR(serverName),
description: errors.join(EOL),
level: azdata.window.MessageLevel.Error
};
this._assessmentStatusIcon.iconPath = IconPathHelper.error;
this._igComponent.value = constants.ASSESSMENT_FAILED(serverName);
this._detailsComponent.value = constants.SKU_RECOMMENDATION_ASSESSMENT_ERROR(serverName);
} else {
this._assessmentStatusIcon.iconPath = IconPathHelper.completedMigration;
this._igComponent.value = constants.ASSESSMENT_COMPLETED(serverName);
this._detailsComponent.value = constants.SKU_RECOMMENDATION_ALL_SUCCESSFUL(this.migrationStateModel._assessmentResults?.databaseAssessments?.length);
}
}
if (this.hasRecommendations() && this.migrationStateModel.hasRecommendedDatabaseListChanged()) {
await this.migrationStateModel.getSkuRecommendations();
}
if (this.hasSavedInfo()) {
if (this.migrationStateModel.savedInfo.migrationTargetType) {
this._rbg.selectedCardId = this.migrationStateModel.savedInfo.migrationTargetType;
await this.refreshCardText();
}
if (this.migrationStateModel.savedInfo.migrationTargetType === MigrationTargetType.SQLMI) {
this.migrationStateModel._miDbs = this.migrationStateModel.savedInfo.databaseList;
} else {
this.migrationStateModel._vmDbs = this.migrationStateModel.savedInfo.databaseList;
}
if (this.migrationStateModel.savedInfo.skuRecommendation) {
const skuRecommendationSavedInfo = this.migrationStateModel.savedInfo.skuRecommendation;
this.migrationStateModel._skuRecommendationPerformanceDataSource = skuRecommendationSavedInfo.skuRecommendationPerformanceDataSource!;
this.migrationStateModel._skuRecommendationPerformanceLocation = skuRecommendationSavedInfo.skuRecommendationPerformanceLocation!;
this.migrationStateModel._skuScalingFactor = skuRecommendationSavedInfo.skuScalingFactor!;
this.migrationStateModel._skuTargetPercentile = skuRecommendationSavedInfo.skuTargetPercentile!;
this.migrationStateModel._skuEnablePreview = skuRecommendationSavedInfo.skuEnablePreview!;
await this.refreshSkuParameters();
switch (this.migrationStateModel._skuRecommendationPerformanceDataSource) {
case PerformanceDataSourceOptions.CollectData: {
this.migrationStateModel._perfDataCollectionStartDate = skuRecommendationSavedInfo.perfDataCollectionStartDate;
// check if collector is still running
await this.migrationStateModel.refreshPerfDataCollection();
if (this.migrationStateModel._perfDataCollectionIsCollecting) {
// user started collecting data, and the collector is still running
const collectionStartTime = new Date(this.migrationStateModel._perfDataCollectionStartDate!);
const expectedRefreshTime = new Date(collectionStartTime.getTime() + this.migrationStateModel.refreshGetSkuRecommendationFrequency);
const timeLeft = Math.abs(new Date().getTime() - expectedRefreshTime.getTime());
await this.migrationStateModel.startSkuTimers(this, timeLeft);
} else {
// user started collecting data, but collector is stopped
// set stop date to some date value
this.migrationStateModel._perfDataCollectionStopDate = this.migrationStateModel._perfDataCollectionStopDate || new Date();
await this.migrationStateModel.getSkuRecommendations();
}
break;
}
case PerformanceDataSourceOptions.OpenExisting: {
await this.migrationStateModel.getSkuRecommendations();
break;
}
const assessmentError = this.migrationStateModel._assessmentResults?.assessmentError;
if (assessmentError) {
errors.push(`message: ${assessmentError.message}${EOL}stack: ${assessmentError.stack}`);
}
if (this.migrationStateModel?._assessmentResults?.errors?.length! > 0) {
errors.push(...this.migrationStateModel._assessmentResults?.errors?.map(
e => `message: ${e.message}${EOL}errorSummary: ${e.errorSummary}${EOL}possibleCauses: ${e.possibleCauses}${EOL}guidance: ${e.guidance}${EOL}errorId: ${e.errorId}`)!);
}
} catch (e) {
errors.push(constants.SKU_RECOMMENDATION_ASSESSMENT_UNEXPECTED_ERROR(serverName, e));
logError(TelemetryViews.MigrationWizardTaSkuRecommendationPage, 'SkuRecommendationUnexpectedError', e);
} finally {
this.migrationStateModel._runAssessments = errors.length > 0;
if (errors.length > 0) {
this.wizard.message = {
text: constants.SKU_RECOMMENDATION_ASSESSMENT_ERROR(serverName),
description: errors.join(EOL),
level: azdata.window.MessageLevel.Error
};
this._assessmentStatusIcon.iconPath = IconPathHelper.error;
this._igComponent.value = constants.ASSESSMENT_FAILED(serverName);
this._detailsComponent.value = constants.SKU_RECOMMENDATION_ASSESSMENT_ERROR(serverName);
} else {
this._assessmentStatusIcon.iconPath = IconPathHelper.completedMigration;
this._igComponent.value = constants.ASSESSMENT_COMPLETED(serverName);
this._detailsComponent.value = constants.SKU_RECOMMENDATION_ALL_SUCCESSFUL(this.migrationStateModel._assessmentResults?.databaseAssessments?.length);
}
}
} else {
// use prior assessment results
this._assessmentStatusIcon.iconPath = IconPathHelper.completedMigration;
this._igComponent.value = constants.ASSESSMENT_COMPLETED(serverName);
this._detailsComponent.value = constants.SKU_RECOMMENDATION_ALL_SUCCESSFUL(this.migrationStateModel._assessmentResults?.databaseAssessments?.length);
}
if (this.migrationStateModel.savedInfo?.migrationTargetType) {
this._rbg.selectedCardId = this.migrationStateModel._targetType;
}
let shouldGetSkuRecommendations = false;
if (this.hasRecommendations() && this.migrationStateModel.hasRecommendedDatabaseListChanged()) {
shouldGetSkuRecommendations = true;
}
if (this.migrationStateModel.savedInfo?.skuRecommendation) {
await this.refreshSkuParameters();
switch (this.migrationStateModel._skuRecommendationPerformanceDataSource) {
case PerformanceDataSourceOptions.CollectData: {
// check if collector is still running
await this.migrationStateModel.refreshPerfDataCollection();
if (this.migrationStateModel._perfDataCollectionIsCollecting) {
// user started collecting data, and the collector is still running
const collectionStartTime = new Date(this.migrationStateModel._perfDataCollectionStartDate!);
const expectedRefreshTime = new Date(collectionStartTime.getTime() + this.migrationStateModel.refreshGetSkuRecommendationFrequency);
const timeLeft = Math.abs(new Date().getTime() - expectedRefreshTime.getTime());
await this.migrationStateModel.startSkuTimers(this, timeLeft);
} else {
// user started collecting data, but collector is stopped
// set stop date to some date value
this.migrationStateModel._perfDataCollectionStopDate = this.migrationStateModel._perfDataCollectionStopDate || new Date();
shouldGetSkuRecommendations = true;
}
break;
}
case PerformanceDataSourceOptions.OpenExisting: {
shouldGetSkuRecommendations = true;
break;
}
}
}
if (shouldGetSkuRecommendations) {
await this.migrationStateModel.getSkuRecommendations();
}
await this.refreshSkuRecommendationComponents();
@@ -582,7 +561,7 @@ export class SKURecommendationPage extends MigrationWizardPage {
display = (this._rbg.selectedCardId
&& (!failedAssessment || this._skipAssessmentCheckbox.checked)
&& this.migrationStateModel._migrationDbs.length > 0)
&& this.migrationStateModel._databasesForMigration?.length > 0)
? 'inline'
: 'none';
@@ -603,7 +582,7 @@ export class SKURecommendationPage extends MigrationWizardPage {
if (this._rbg.selectedCardId === undefined || this._rbg.selectedCardId === '') {
errors.push(constants.SELECT_TARGET_TO_CONTINUE);
}
if (this.migrationStateModel._migrationDbs.length === 0) {
if (this.migrationStateModel._databasesForMigration.length === 0) {
errors.push(constants.SELECT_DATABASE_TO_MIGRATE);
}
@@ -638,9 +617,9 @@ export class SKURecommendationPage extends MigrationWizardPage {
public async refreshCardText(showLoadingIcon: boolean = true): Promise<void> {
this._rbgLoader.loading = showLoadingIcon && true;
if (this._rbg.selectedCardId === MigrationTargetType.SQLMI) {
this.migrationStateModel._migrationDbs = this.migrationStateModel._miDbs;
this.migrationStateModel._databasesForMigration = this.migrationStateModel._miDbs;
} else {
this.migrationStateModel._migrationDbs = this.migrationStateModel._vmDbs;
this.migrationStateModel._databasesForMigration = this.migrationStateModel._vmDbs;
}
const dbCount = this.migrationStateModel._assessmentResults?.databaseAssessments?.length;
@@ -1188,10 +1167,6 @@ export class SKURecommendationPage extends MigrationWizardPage {
await this.refreshCardText(false);
}
private hasSavedInfo(): boolean {
return this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.SKURecommendation);
}
private hasRecommendations(): boolean {
return this.migrationStateModel._skuRecommendationResults?.recommendations && !this.migrationStateModel._skuRecommendationResults?.recommendationError ? true : false;
}

View File

@@ -6,14 +6,12 @@
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { MigrationWizardPage } from '../models/migrationWizardPage';
import { MigrationMode, MigrationStateModel, MigrationTargetType, NetworkContainerType, Page, StateChangeEvent } from '../models/stateMachine';
import { MigrationMode, MigrationStateModel, MigrationTargetType, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
import * as constants from '../constants/strings';
import { createHeadingTextComponent, createInformationRow, createLabelTextComponent } from './wizardController';
import { getResourceGroupFromId, Subscription } from '../api/azure';
import { getResourceGroupFromId } from '../api/azure';
import { TargetDatabaseSummaryDialog } from '../dialog/targetDatabaseSummary/targetDatabaseSummaryDialog';
import * as styles from '../constants/styles';
import { azureResource } from 'azureResource';
import { Tenant } from 'azurecore';
export class SummaryPage extends MigrationWizardPage {
private _view!: azdata.ModelView;
@@ -47,30 +45,10 @@ export class SummaryPage extends MigrationWizardPage {
}
public async onPageEnter(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
if (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.Summary) {
this.migrationStateModel._databaseBackup.networkContainerType = <NetworkContainerType>this.migrationStateModel.savedInfo.networkContainerType;
this.migrationStateModel._databaseBackup.networkShares = this.migrationStateModel.savedInfo.networkShares;
this.migrationStateModel._databaseBackup.subscription = <Subscription>this.migrationStateModel.savedInfo.targetSubscription;
this.migrationStateModel._databaseBackup.blobs = this.migrationStateModel.savedInfo.blobs;
this.migrationStateModel._targetDatabaseNames = this.migrationStateModel.savedInfo.targetDatabaseNames;
this.migrationStateModel._targetType = <MigrationTargetType>this.migrationStateModel.savedInfo.migrationTargetType;
this.migrationStateModel._databaseAssessment = <string[]>this.migrationStateModel.savedInfo.databaseAssessment;
this.migrationStateModel._migrationDbs = this.migrationStateModel.savedInfo.databaseList;
this.migrationStateModel._targetSubscription = <azureResource.AzureResourceSubscription>this.migrationStateModel.savedInfo.subscription;
this.migrationStateModel._location = <azureResource.AzureLocation>this.migrationStateModel.savedInfo.location;
this.migrationStateModel._resourceGroup = <azureResource.AzureResourceResourceGroup>this.migrationStateModel.savedInfo.resourceGroup;
this.migrationStateModel._targetServerInstance = <azureResource.AzureSqlManagedInstance>this.migrationStateModel.savedInfo.targetServerInstance;
this.migrationStateModel.databaseSelectorTableValues = this.migrationStateModel.savedInfo.selectedDatabases;
this.migrationStateModel._azureAccount = <azdata.Account>this.migrationStateModel.savedInfo.azureAccount;
this.migrationStateModel._azureTenant = <Tenant>this.migrationStateModel.savedInfo.azureTenant;
}
const targetDatabaseSummary = new TargetDatabaseSummaryDialog(this.migrationStateModel);
const targetDatabaseHyperlink = this._view.modelBuilder.hyperlink().withProps({
url: '',
label: this.migrationStateModel._migrationDbs.length.toString(),
label: this.migrationStateModel._databasesForMigration?.length.toString(),
CSSStyles: {
...styles.BODY_CSS,
'margin': '0px',
@@ -128,7 +106,7 @@ export class SummaryPage extends MigrationWizardPage {
await createHeadingTextComponent(this._view, constants.IR_PAGE_TITLE),
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name),
createInformationRow(this._view, constants.LOCATION, this.migrationStateModel._sqlMigrationService?.location!),
createInformationRow(this._view, constants.LOCATION, await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._sqlMigrationService?.location!)),
createInformationRow(this._view, constants.RESOURCE_GROUP, this.migrationStateModel._sqlMigrationService?.properties?.resourceGroup!),
createInformationRow(this._view, constants.IR_PAGE_TITLE, this.migrationStateModel._sqlMigrationService?.name!)
]

View File

@@ -7,11 +7,11 @@ import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { EOL } from 'os';
import { MigrationWizardPage } from '../models/migrationWizardPage';
import { MigrationStateModel, MigrationTargetType, Page, StateChangeEvent } from '../models/stateMachine';
import { MigrationStateModel, MigrationTargetType, StateChangeEvent } from '../models/stateMachine';
import * as constants from '../constants/strings';
import * as styles from '../constants/styles';
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
import { deepClone, findDropDownItemIndex, selectDropDownIndex } from '../api/utils';
import { deepClone, findDropDownItemIndex, selectDropDownIndex, selectDefaultDropdownValue } from '../api/utils';
export class TargetSelectionPage extends MigrationWizardPage {
private _view!: azdata.ModelView;
@@ -27,7 +27,6 @@ export class TargetSelectionPage extends MigrationWizardPage {
private _azureResourceDropdownLabel!: azdata.TextComponent;
private _azureResourceDropdown!: azdata.DropDownComponent;
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
super(wizard, azdata.window.createWizardPage(constants.AZURE_SQL_TARGET_PAGE_TITLE), migrationStateModel);
}
@@ -73,19 +72,21 @@ export class TargetSelectionPage extends MigrationWizardPage {
}
public async onPageEnter(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
switch (this.migrationStateModel._targetType) {
case MigrationTargetType.SQLMI:
this._pageDescription.value = constants.AZURE_SQL_TARGET_PAGE_DESCRIPTION(constants.SKU_RECOMMENDATION_MI_CARD_TEXT);
this._azureResourceDropdownLabel.value = constants.AZURE_SQL_DATABASE_MANAGED_INSTANCE;
this._azureResourceDropdown.ariaLabel = constants.AZURE_SQL_DATABASE_MANAGED_INSTANCE;
break;
case MigrationTargetType.SQLVM:
this._pageDescription.value = constants.AZURE_SQL_TARGET_PAGE_DESCRIPTION(constants.SKU_RECOMMENDATION_VM_CARD_TEXT);
this._azureResourceDropdownLabel.value = constants.AZURE_SQL_DATABASE_VIRTUAL_MACHINE;
this._azureResourceDropdown.ariaLabel = constants.AZURE_SQL_DATABASE_VIRTUAL_MACHINE;
break;
}
await this.populateResourceInstanceDropdown();
await this.populateAzureAccountsDropdown();
this.wizard.registerNavigationValidator((pageChangeInfo) => {
@@ -99,22 +100,39 @@ export class TargetSelectionPage extends MigrationWizardPage {
return true;
}
if ((<azdata.CategoryValue>this._azureSubscriptionDropdown.value)?.displayName === constants.NO_SUBSCRIPTIONS_FOUND) {
if (!this.migrationStateModel._azureAccount) {
errors.push(constants.INVALID_ACCOUNT_ERROR);
}
if (!this.migrationStateModel._targetSubscription ||
(<azdata.CategoryValue>this._azureSubscriptionDropdown.value)?.displayName === constants.NO_SUBSCRIPTIONS_FOUND) {
errors.push(constants.INVALID_SUBSCRIPTION_ERROR);
}
if ((<azdata.CategoryValue>this._azureLocationDropdown.value)?.displayName === constants.NO_LOCATION_FOUND) {
if (!this.migrationStateModel._location ||
(<azdata.CategoryValue>this._azureLocationDropdown.value)?.displayName === constants.NO_LOCATION_FOUND) {
errors.push(constants.INVALID_LOCATION_ERROR);
}
if ((<azdata.CategoryValue>this._azureResourceGroupDropdown.value)?.displayName === constants.RESOURCE_GROUP_NOT_FOUND) {
if (!this.migrationStateModel._resourceGroup ||
(<azdata.CategoryValue>this._azureResourceGroupDropdown.value)?.displayName === constants.RESOURCE_GROUP_NOT_FOUND) {
errors.push(constants.INVALID_RESOURCE_GROUP_ERROR);
}
const resourceDropdownValue = (<azdata.CategoryValue>this._azureResourceDropdown.value)?.displayName;
if (resourceDropdownValue === constants.NO_MANAGED_INSTANCE_FOUND) {
errors.push(constants.INVALID_MANAGED_INSTANCE_ERROR);
}
else if (resourceDropdownValue === constants.NO_VIRTUAL_MACHINE_FOUND) {
errors.push(constants.INVALID_VIRTUAL_MACHINE_ERROR);
switch (this.migrationStateModel._targetType) {
case MigrationTargetType.SQLMI: {
if (!this.migrationStateModel._targetServerInstance ||
resourceDropdownValue === constants.NO_MANAGED_INSTANCE_FOUND) {
errors.push(constants.INVALID_MANAGED_INSTANCE_ERROR);
}
break;
}
case MigrationTargetType.SQLVM: {
if (!this.migrationStateModel._targetServerInstance ||
resourceDropdownValue === constants.NO_VIRTUAL_MACHINE_FOUND) {
errors.push(constants.INVALID_VIRTUAL_MACHINE_ERROR);
}
break;
}
}
if (errors.length > 0) {
@@ -175,8 +193,10 @@ export class TargetSelectionPage extends MigrationWizardPage {
});
}
await this._azureAccountsDropdown.validate();
await this.populateSubscriptionDropdown();
} else {
this.migrationStateModel._azureAccount = undefined!;
}
await this.populateSubscriptionDropdown();
}));
const linkAccountButton = this._view.modelBuilder.hyperlink()
@@ -236,11 +256,7 @@ export class TargetSelectionPage extends MigrationWizardPage {
this.migrationStateModel._azureTenant = deepClone(selectedTenant);
if (selectedIndex > -1) {
this.migrationStateModel._azureAccount.properties.tenants = [this.migrationStateModel.getTenant(selectedIndex)];
this.migrationStateModel._subscriptions = undefined!;
this.migrationStateModel._targetSubscription = undefined!;
this.migrationStateModel._databaseBackup.subscription = undefined!;
}
}));
this._accountTenantFlexContainer = this._view.modelBuilder.flexContainer()
@@ -285,10 +301,12 @@ export class TargetSelectionPage extends MigrationWizardPage {
if (selectedIndex > -1 &&
value !== constants.NO_SUBSCRIPTIONS_FOUND) {
this.migrationStateModel._targetSubscription = this.migrationStateModel.getSubscription(selectedIndex);
this.migrationStateModel._targetServerInstance = undefined!;
this.migrationStateModel._sqlMigrationService = undefined!;
await this.populateLocationDropdown();
} else {
this.migrationStateModel._targetSubscription = undefined!;
}
this.migrationStateModel.refreshDatabaseBackupPage = true;
await this.populateLocationDropdown();
await this.populateResourceGroupDropdown();
}));
const azureLocationLabel = this._view.modelBuilder.text().withProps({
@@ -315,8 +333,11 @@ export class TargetSelectionPage extends MigrationWizardPage {
if (selectedIndex > -1 &&
value !== constants.NO_LOCATION_FOUND) {
this.migrationStateModel._location = this.migrationStateModel.getLocation(selectedIndex);
await this.populateResourceGroupDropdown();
} else {
this.migrationStateModel._location = undefined!;
}
this.migrationStateModel.refreshDatabaseBackupPage = true;
await this.populateResourceInstanceDropdown();
}));
const azureResourceGroupLabel = this._view.modelBuilder.text().withProps({
@@ -340,12 +361,13 @@ export class TargetSelectionPage extends MigrationWizardPage {
}).component();
this._disposables.push(this._azureResourceGroupDropdown.onValueChanged(async (value) => {
const selectedIndex = findDropDownItemIndex(this._azureResourceGroupDropdown, value);
if (selectedIndex > -1) {
if (value !== constants.RESOURCE_GROUP_NOT_FOUND) {
this.migrationStateModel._resourceGroup = this.migrationStateModel.getAzureResourceGroup(selectedIndex);
}
await this.populateResourceInstanceDropdown();
if (selectedIndex > -1 &&
value !== constants.RESOURCE_GROUP_NOT_FOUND) {
this.migrationStateModel._resourceGroup = this.migrationStateModel.getAzureResourceGroup(selectedIndex);
} else {
this.migrationStateModel._resourceGroup = undefined!;
}
await this.populateResourceInstanceDropdown();
}));
this._azureResourceDropdownLabel = this._view.modelBuilder.text().withProps({
@@ -367,7 +389,7 @@ export class TargetSelectionPage extends MigrationWizardPage {
'margin-top': '-1em'
},
}).component();
this._disposables.push(this._azureResourceDropdown.onValueChanged(value => {
this._disposables.push(this._azureResourceDropdown.onValueChanged(async (value) => {
const selectedIndex = findDropDownItemIndex(this._azureResourceDropdown, value);
if (selectedIndex > -1 &&
value !== constants.NO_MANAGED_INSTANCE_FOUND &&
@@ -383,6 +405,8 @@ export class TargetSelectionPage extends MigrationWizardPage {
this.migrationStateModel._targetServerInstance = this.migrationStateModel.getManagedInstance(selectedIndex);
break;
}
} else {
this.migrationStateModel._targetServerInstance = undefined!;
}
}));
@@ -404,145 +428,91 @@ export class TargetSelectionPage extends MigrationWizardPage {
private async populateAzureAccountsDropdown(): Promise<void> {
try {
this._azureAccountsDropdown.loading = true;
this._azureSubscriptionDropdown.loading = true;
this._azureLocationDropdown.loading = true;
this._azureResourceGroupDropdown.loading = true;
this._azureResourceDropdown.loading = true;
this.updateDropdownLoadingStatus(TargetDropDowns.AzureAccount, true);
this._azureAccountsDropdown.values = await this.migrationStateModel.getAccountValues();
if (this.hasSavedInfo() && this._azureAccountsDropdown.values) {
(<azdata.CategoryValue[]>this._azureAccountsDropdown.values)?.forEach((account, index) => {
if ((<azdata.CategoryValue>account).name.toLowerCase() === this.migrationStateModel.savedInfo.azureAccount?.displayInfo.userId.toLowerCase()) {
selectDropDownIndex(this._azureAccountsDropdown, index);
}
});
} else {
selectDropDownIndex(this._azureAccountsDropdown, 0);
}
selectDefaultDropdownValue(this._azureAccountsDropdown, this.migrationStateModel._azureAccount?.displayInfo?.userId, false);
} finally {
this._azureAccountsDropdown.loading = false;
this._azureSubscriptionDropdown.loading = false;
this._azureLocationDropdown.loading = false;
this._azureResourceGroupDropdown.loading = false;
this._azureResourceDropdown.loading = false;
this.updateDropdownLoadingStatus(TargetDropDowns.AzureAccount, false);
}
}
private async populateSubscriptionDropdown(): Promise<void> {
try {
this._azureSubscriptionDropdown.loading = true;
this._azureLocationDropdown.loading = true;
this._azureResourceGroupDropdown.loading = true;
this._azureResourceDropdown.loading = true;
this.updateDropdownLoadingStatus(TargetDropDowns.Subscription, true);
this._azureSubscriptionDropdown.values = await this.migrationStateModel.getSubscriptionsDropdownValues();
if (this.hasSavedInfo() && this._azureSubscriptionDropdown.values) {
this._azureSubscriptionDropdown.values!.forEach((subscription, index) => {
if ((<azdata.CategoryValue>subscription).name.toLowerCase() === this.migrationStateModel.savedInfo?.subscription?.id.toLowerCase()) {
selectDropDownIndex(this._azureSubscriptionDropdown, index);
}
});
} else {
selectDropDownIndex(this._azureSubscriptionDropdown, 0);
}
selectDefaultDropdownValue(this._azureSubscriptionDropdown, this.migrationStateModel._targetSubscription?.id, false);
} catch (e) {
console.log(e);
} finally {
this._azureSubscriptionDropdown.loading = false;
this._azureLocationDropdown.loading = false;
this._azureResourceGroupDropdown.loading = false;
this._azureResourceDropdown.loading = false;
this.updateDropdownLoadingStatus(TargetDropDowns.Subscription, false);
}
}
public async populateLocationDropdown(): Promise<void> {
try {
this._azureLocationDropdown.loading = true;
this._azureResourceGroupDropdown.loading = true;
this._azureResourceDropdown.loading = true;
this.updateDropdownLoadingStatus(TargetDropDowns.Location, true);
this._azureLocationDropdown.values = await this.migrationStateModel.getAzureLocationDropdownValues(this.migrationStateModel._targetSubscription);
if (this.hasSavedInfo() && this._azureLocationDropdown.values) {
this._azureLocationDropdown.values.forEach((location, index) => {
if ((<azdata.CategoryValue>location)?.displayName.toLowerCase() === this.migrationStateModel.savedInfo?.location?.displayName.toLowerCase()) {
selectDropDownIndex(this._azureLocationDropdown, index);
}
});
} else {
selectDropDownIndex(this._azureLocationDropdown, 0);
}
selectDefaultDropdownValue(this._azureLocationDropdown, this.migrationStateModel._location?.displayName, true);
} catch (e) {
console.log(e);
} finally {
this._azureLocationDropdown.loading = false;
this._azureResourceGroupDropdown.loading = false;
this._azureResourceDropdown.loading = false;
this.updateDropdownLoadingStatus(TargetDropDowns.Location, false);
}
}
public async populateResourceGroupDropdown(): Promise<void> {
try {
this._azureResourceGroupDropdown.loading = true;
this._azureResourceDropdown.loading = true;
this.updateDropdownLoadingStatus(TargetDropDowns.ResourceGroup, true);
this._azureResourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._targetSubscription);
if (this.hasSavedInfo() && this._azureResourceGroupDropdown.values) {
this._azureResourceGroupDropdown.values.forEach((resourceGroup, index) => {
if ((<azdata.CategoryValue>resourceGroup)?.name.toLowerCase() === this.migrationStateModel.savedInfo?.resourceGroup?.id.toLowerCase()) {
selectDropDownIndex(this._azureResourceGroupDropdown, index);
}
});
} else {
selectDropDownIndex(this._azureResourceGroupDropdown, 0);
}
selectDefaultDropdownValue(this._azureResourceGroupDropdown, this.migrationStateModel._resourceGroup?.id, false);
} catch (e) {
console.log(e);
} finally {
this._azureResourceGroupDropdown.loading = false;
this._azureResourceDropdown.loading = false;
this.updateDropdownLoadingStatus(TargetDropDowns.ResourceGroup, false);
}
}
private async populateResourceInstanceDropdown(): Promise<void> {
try {
this._azureResourceDropdown.loading = true;
this.updateDropdownLoadingStatus(TargetDropDowns.ResourceInstance, true);
switch (this.migrationStateModel._targetType) {
case MigrationTargetType.SQLVM:
this._azureResourceDropdown.values = await this.migrationStateModel.getSqlVirtualMachineValues(
this.migrationStateModel._targetSubscription,
this.migrationStateModel._location,
this.migrationStateModel._resourceGroup);
case MigrationTargetType.SQLMI: {
this._azureResourceDropdown.values = await this.migrationStateModel.getManagedInstanceValues(this.migrationStateModel._targetSubscription, this.migrationStateModel._location, this.migrationStateModel._resourceGroup);
break;
case MigrationTargetType.SQLMI:
this._azureResourceDropdown.values = await this.migrationStateModel.getManagedInstanceValues(
this.migrationStateModel._targetSubscription,
this.migrationStateModel._location,
this.migrationStateModel._resourceGroup);
}
case MigrationTargetType.SQLVM: {
this._azureResourceDropdown.values = await this.migrationStateModel.getSqlVirtualMachineValues(this.migrationStateModel._targetSubscription, this.migrationStateModel._location, this.migrationStateModel._resourceGroup);
break;
}
}
if (this.hasSavedInfo() && this._azureResourceDropdown.values) {
this._azureResourceDropdown.values.forEach((resource, index) => {
if ((<azdata.CategoryValue>resource).name.toLowerCase() === this.migrationStateModel.savedInfo?.targetServerInstance?.name.toLowerCase()) {
selectDropDownIndex(this._azureResourceDropdown, index);
}
});
} else {
selectDropDownIndex(this._azureResourceDropdown, 0);
}
selectDefaultDropdownValue(this._azureResourceDropdown, this.migrationStateModel._targetServerInstance?.name, true);
} catch (e) {
console.log(e);
} finally {
this._azureResourceDropdown.loading = false;
this.updateDropdownLoadingStatus(TargetDropDowns.ResourceInstance, false);
}
}
private hasSavedInfo(): boolean {
return this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.TargetSelection);
private updateDropdownLoadingStatus(dropdown: TargetDropDowns, loading: boolean): void {
switch (dropdown) {
case TargetDropDowns.AzureAccount:
this._azureAccountsDropdown.loading = loading;
case TargetDropDowns.Subscription:
this._azureSubscriptionDropdown.loading = loading;
case TargetDropDowns.Location:
this._azureLocationDropdown.loading = loading;
case TargetDropDowns.ResourceGroup:
this._azureResourceGroupDropdown.loading = loading;
case TargetDropDowns.ResourceInstance:
this._azureResourceDropdown.loading = loading;
}
}
}
export enum TargetDropDowns {
AzureAccount,
Subscription,
Location,
ResourceGroup,
ResourceInstance,
}