mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-23 01:25:38 -05:00
Fixing bugs for migration extension private preview 1. (#14872)
* Fixing Database backup page target layout * Filtering out Azure sql db issues from assessment results Correcting the database count for issued databases in sku rec page. * Adding copy migration details button to migration status * Adding start migration button to toolbar * Fixing a syntax error in package.json * Adding rg and location to target selection page Filtering storage account by target location. * Fixing dashboard title to azure sql migration * Not making assessment targets selected by default. * Adding tooltip for database and instance table items. * Fixing duplicate task widget * Some fixes mentioned in the PR Localizing button text renaming a var changing null to undefined. * Adding enum for Migration target types * Fixing a critical multi db migration bug because of unhandled race condition * Adding Azure location api to azure core * Adding source database info in status
This commit is contained in:
@@ -332,12 +332,32 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
this.migrationStateModel._databaseBackup.storageAccount = this.migrationStateModel.getStorageAccount(value.index);
|
||||
}
|
||||
});
|
||||
|
||||
const networkLocationInputBoxLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.DATABASE_BACKUP_NETWORK_SHARE_LOCATION_LABEL,
|
||||
requiredIndicator: true
|
||||
}).component();
|
||||
const networkLocationInputBox = this._view.modelBuilder.inputBox().withProps({
|
||||
placeHolder: '\\\\Servername.domainname.com\\Backupfolder',
|
||||
required: true,
|
||||
validationErrorMessage: constants.INVALID_NETWORK_SHARE_LOCATION
|
||||
}).withValidation((component) => {
|
||||
if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
if (component.value) {
|
||||
if (!/(?<=\\\\)[^\\]*/.test(component.value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
networkLocationInputBox.onTextChanged((value) => {
|
||||
this.validateFields();
|
||||
this.migrationStateModel._databaseBackup.networkShareLocation = value;
|
||||
});
|
||||
|
||||
const networkShareDatabaseConfigHeader = view.modelBuilder.text().withProps({
|
||||
value: constants.ENTER_NETWORK_SHARE_INFORMATION
|
||||
}).component();
|
||||
|
||||
this._networkShareDatabaseConfigContainer = view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
@@ -347,14 +367,16 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
[
|
||||
azureAccountHelpText,
|
||||
networkShareHelpText,
|
||||
subscriptionLabel,
|
||||
this._networkShareContainerSubscriptionDropdown,
|
||||
storageAccountLabel,
|
||||
this._networkShareContainerStorageAccountDropdown,
|
||||
networkLocationInputBoxLabel,
|
||||
networkLocationInputBox,
|
||||
windowsUserAccountLabel,
|
||||
this._windowsUserAccountText,
|
||||
passwordLabel,
|
||||
this._passwordText,
|
||||
subscriptionLabel,
|
||||
this._networkShareContainerSubscriptionDropdown,
|
||||
storageAccountLabel,
|
||||
this._networkShareContainerStorageAccountDropdown,
|
||||
networkShareDatabaseConfigHeader,
|
||||
this._networkShareDatabaseConfigContainer
|
||||
]
|
||||
@@ -374,7 +396,6 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
this._fileShareDropdowns = [];
|
||||
this._blobContainerDropdowns = [];
|
||||
this.migrationStateModel._targetDatabaseNames = [];
|
||||
this.migrationStateModel._databaseBackup.networkShareLocations = [];
|
||||
this.migrationStateModel._databaseBackup.fileShares = [];
|
||||
this.migrationStateModel._databaseBackup.blobContainers = [];
|
||||
this._networkShareDatabaseConfigContainer.clearItems();
|
||||
@@ -389,42 +410,16 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
requiredIndicator: true
|
||||
}).component();
|
||||
const targetNameNetworkInputBox = this._view.modelBuilder.inputBox().withProps({
|
||||
required: true
|
||||
required: true,
|
||||
value: db
|
||||
}).component();
|
||||
targetNameNetworkInputBox.onTextChanged((value) => {
|
||||
this.migrationStateModel._targetDatabaseNames[index] = value;
|
||||
});
|
||||
|
||||
const networkLocationInputBoxLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.TARGET_NETWORK_SHARE_LOCATION(db),
|
||||
requiredIndicator: true
|
||||
}).component();
|
||||
const networkLocationInputBox = this._view.modelBuilder.inputBox().withProps({
|
||||
placeHolder: '\\\\Servername.domainname.com\\Backupfolder',
|
||||
required: true,
|
||||
validationErrorMessage: constants.INVALID_NETWORK_SHARE_LOCATION
|
||||
}).withValidation((component) => {
|
||||
if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
if (component.value) {
|
||||
if (!/(?<=\\\\)[^\\]*/.test(component.value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
networkLocationInputBox.onTextChanged((value) => {
|
||||
this.validateFields();
|
||||
this.migrationStateModel._databaseBackup.networkShareLocations[index] = value;
|
||||
});
|
||||
this.migrationStateModel._databaseBackup.networkShareLocations.push(undefined!);
|
||||
this._networkShareLocations.push(networkLocationInputBox);
|
||||
this._networkShareDatabaseConfigContainer.addItems(
|
||||
[
|
||||
targetNameNetworkInputBoxLabel,
|
||||
targetNameNetworkInputBox,
|
||||
networkLocationInputBoxLabel,
|
||||
networkLocationInputBox
|
||||
targetNameNetworkInputBox
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ export class SKURecommendationPage extends MigrationWizardPage {
|
||||
private _chooseTargetComponent!: azdata.DivContainer;
|
||||
private _azureSubscriptionText!: azdata.TextComponent;
|
||||
private _managedInstanceSubscriptionDropdown!: azdata.DropDownComponent;
|
||||
private _azureLocationDropdown!: azdata.DropDownComponent;
|
||||
private _azureResourceGroupDropdown!: azdata.DropDownComponent;
|
||||
private _resourceDropdownLabel!: azdata.TextComponent;
|
||||
private _resourceDropdown!: azdata.DropDownComponent;
|
||||
private _rbg!: azdata.RadioCardGroupComponent;
|
||||
@@ -66,6 +68,35 @@ export class SKURecommendationPage extends MigrationWizardPage {
|
||||
this.migrationStateModel._targetSubscription = this.migrationStateModel.getSubscription(e.index);
|
||||
this.migrationStateModel._targetServerInstance = undefined!;
|
||||
this.migrationStateModel._sqlMigrationService = undefined!;
|
||||
this.populateLocationAndResourceGroupDropdown();
|
||||
}
|
||||
});
|
||||
this._resourceDropdownLabel = view.modelBuilder.text().withProps({
|
||||
value: constants.MANAGED_INSTANCE
|
||||
}).component();
|
||||
|
||||
const azureLocationLabel = view.modelBuilder.text().withProps({
|
||||
value: constants.LOCATION
|
||||
}).component();
|
||||
this._azureLocationDropdown = view.modelBuilder.dropDown().component();
|
||||
this._azureLocationDropdown.onValueChanged((e) => {
|
||||
if (e.selected) {
|
||||
this.migrationStateModel._location = this.migrationStateModel.getLocation(e.index);
|
||||
this.populateResourceInstanceDropdown();
|
||||
}
|
||||
});
|
||||
this._resourceDropdownLabel = view.modelBuilder.text().withProps({
|
||||
value: constants.MANAGED_INSTANCE
|
||||
}).component();
|
||||
|
||||
|
||||
const azureResourceGroupLabel = view.modelBuilder.text().withProps({
|
||||
value: constants.RESOURCE_GROUP
|
||||
}).component();
|
||||
this._azureResourceGroupDropdown = view.modelBuilder.dropDown().component();
|
||||
this._azureResourceGroupDropdown.onValueChanged((e) => {
|
||||
if (e.selected) {
|
||||
this.migrationStateModel._resourceGroup = this.migrationStateModel.getAzureResourceGroup(e.index);
|
||||
this.populateResourceInstanceDropdown();
|
||||
}
|
||||
});
|
||||
@@ -91,6 +122,10 @@ export class SKURecommendationPage extends MigrationWizardPage {
|
||||
[
|
||||
managedInstanceSubscriptionDropdownLabel,
|
||||
this._managedInstanceSubscriptionDropdown,
|
||||
azureLocationLabel,
|
||||
this._azureLocationDropdown,
|
||||
azureResourceGroupLabel,
|
||||
this._azureResourceGroupDropdown,
|
||||
this._resourceDropdownLabel,
|
||||
this._resourceDropdown
|
||||
]
|
||||
@@ -284,16 +319,30 @@ export class SKURecommendationPage extends MigrationWizardPage {
|
||||
}
|
||||
}
|
||||
|
||||
public async populateLocationAndResourceGroupDropdown(): Promise<void> {
|
||||
this._azureResourceGroupDropdown.loading = true;
|
||||
this._azureLocationDropdown.loading = true;
|
||||
try {
|
||||
this._azureResourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._targetSubscription);
|
||||
this._azureLocationDropdown.values = await this.migrationStateModel.getAzureLocationDropdownValues(this.migrationStateModel._targetSubscription);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
} finally {
|
||||
this._azureResourceGroupDropdown.loading = false;
|
||||
this._azureLocationDropdown.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async populateResourceInstanceDropdown(): Promise<void> {
|
||||
this._resourceDropdown.loading = true;
|
||||
try {
|
||||
if (this._rbg.selectedCardId === MigrationTargetType.SQLVM) {
|
||||
this._resourceDropdownLabel.value = constants.AZURE_SQL_DATABASE_VIRTUAL_MACHINE;
|
||||
this._resourceDropdown.values = await this.migrationStateModel.getSqlVirtualMachineValues(this.migrationStateModel._targetSubscription);
|
||||
this._resourceDropdown.values = await this.migrationStateModel.getSqlVirtualMachineValues(this.migrationStateModel._targetSubscription, this.migrationStateModel._location, this.migrationStateModel._resourceGroup);
|
||||
|
||||
} else {
|
||||
this._resourceDropdownLabel.value = constants.AZURE_SQL_DATABASE_MANAGED_INSTANCE;
|
||||
this._resourceDropdown.values = await this.migrationStateModel.getManagedInstanceValues(this.migrationStateModel._targetSubscription);
|
||||
this._resourceDropdown.values = await this.migrationStateModel.getManagedInstanceValues(this.migrationStateModel._targetSubscription, this.migrationStateModel._location, this.migrationStateModel._resourceGroup);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
@@ -322,6 +371,13 @@ export class SKURecommendationPage extends MigrationWizardPage {
|
||||
if ((<azdata.CategoryValue>this._managedInstanceSubscriptionDropdown.value).displayName === constants.NO_SUBSCRIPTIONS_FOUND) {
|
||||
errors.push(constants.INVALID_SUBSCRIPTION_ERROR);
|
||||
}
|
||||
if ((<azdata.CategoryValue>this._azureLocationDropdown.value).displayName === constants.NO_LOCATION_FOUND) {
|
||||
errors.push(constants.INVALID_LOCATION_ERROR);
|
||||
}
|
||||
|
||||
if ((<azdata.CategoryValue>this._managedInstanceSubscriptionDropdown.value).displayName === constants.RESOURCE_GROUP_NOT_FOUND) {
|
||||
errors.push(constants.INVALID_RESOURCE_GROUP_ERROR);
|
||||
}
|
||||
const resourceDropdownValue = (<azdata.CategoryValue>this._resourceDropdown.value).displayName;
|
||||
if (resourceDropdownValue === constants.NO_MANAGED_INSTANCE_FOUND) {
|
||||
errors.push(constants.NO_MANAGED_INSTANCE_FOUND);
|
||||
@@ -377,8 +433,8 @@ export class SKURecommendationPage extends MigrationWizardPage {
|
||||
if (this.migrationStateModel._assessmentResults) {
|
||||
const dbCount = this.migrationStateModel._assessmentResults.databaseAssessments.length;
|
||||
|
||||
const dbWithIssuesCount = this.migrationStateModel._assessmentResults.databaseAssessments.filter(db => db.issues.length > 0).length;
|
||||
const miCardText = `${dbWithIssuesCount} out of ${dbCount} databases can be migrated (${this.migrationStateModel._miDbs.length} selected)`;
|
||||
const dbWithoutIssuesCount = this.migrationStateModel._assessmentResults.databaseAssessments.filter(db => db.issues.length === 0).length;
|
||||
const miCardText = `${dbWithoutIssuesCount} out of ${dbCount} databases can be migrated (${this.migrationStateModel._miDbs.length} selected)`;
|
||||
this._rbg.cards[0].descriptions[1].textValue = miCardText;
|
||||
|
||||
const vmCardText = `${dbCount} out of ${dbCount} databases can be migrated (${this.migrationStateModel._vmDbs.length} selected)`;
|
||||
|
||||
@@ -72,6 +72,7 @@ export class SummaryPage extends MigrationWizardPage {
|
||||
flexContainer.addItems(
|
||||
[
|
||||
createInformationRow(this._view, constants.TYPE, constants.NETWORK_SHARE),
|
||||
createInformationRow(this._view, constants.DATABASE_BACKUP_NETWORK_SHARE_LOCATION_LABEL, this.migrationStateModel._databaseBackup.networkShareLocation),
|
||||
createInformationRow(this._view, constants.USER_ACCOUNT, this.migrationStateModel._databaseBackup.windowsUser),
|
||||
createInformationRow(this._view, constants.SUMMARY_AZURE_STORAGE_SUBSCRIPTION, this.migrationStateModel._databaseBackup.subscription.name),
|
||||
createInformationRow(this._view, constants.SUMMARY_AZURE_STORAGE, this.migrationStateModel._databaseBackup.storageAccount.name),
|
||||
@@ -80,7 +81,6 @@ export class SummaryPage extends MigrationWizardPage {
|
||||
);
|
||||
this.migrationStateModel._migrationDbs.forEach((db, index) => {
|
||||
flexContainer.addItem(createInformationRow(this._view, constants.TARGET_NAME_FOR_DATABASE(db), this.migrationStateModel._targetDatabaseNames[index]));
|
||||
flexContainer.addItem(createInformationRow(this._view, constants.TARGET_NETWORK_SHARE_LOCATION(db), this.migrationStateModel._databaseBackup.networkShareLocations[index]));
|
||||
});
|
||||
break;
|
||||
case NetworkContainerType.FILE_SHARE:
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../constants/strings';
|
||||
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
||||
|
||||
export class TempTargetSelectionPage extends MigrationWizardPage {
|
||||
|
||||
private _managedInstanceSubscriptionDropdown!: azdata.DropDownComponent;
|
||||
private _managedInstanceDropdown!: azdata.DropDownComponent;
|
||||
|
||||
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
|
||||
super(wizard, azdata.window.createWizardPage(constants.TARGET_SELECTION_PAGE_TITLE), migrationStateModel);
|
||||
}
|
||||
|
||||
protected async registerContent(view: azdata.ModelView): Promise<void> {
|
||||
|
||||
const managedInstanceSubscriptionDropdownLabel = view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.SUBSCRIPTION
|
||||
}).component();
|
||||
|
||||
this._managedInstanceSubscriptionDropdown = view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH
|
||||
}).component();
|
||||
this._managedInstanceSubscriptionDropdown.onValueChanged((e) => {
|
||||
if (e.selected) {
|
||||
this.migrationStateModel._targetSubscription = this.migrationStateModel.getSubscription(e.index);
|
||||
this.migrationStateModel._targetServerInstance = undefined!;
|
||||
this.migrationStateModel._sqlMigrationService = undefined!;
|
||||
this.populateManagedInstanceDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
const managedInstanceDropdownLabel = view.modelBuilder.text().withProps({
|
||||
value: constants.MANAGED_INSTANCE
|
||||
}).component();
|
||||
|
||||
this._managedInstanceDropdown = view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH
|
||||
}).component();
|
||||
this._managedInstanceDropdown.onValueChanged((e) => {
|
||||
if (e.selected) {
|
||||
this.migrationStateModel._sqlMigrationServices = undefined!;
|
||||
this.migrationStateModel._targetServerInstance = this.migrationStateModel.getManagedInstance(e.index);
|
||||
}
|
||||
});
|
||||
|
||||
const targetContainer = view.modelBuilder.flexContainer().withItems(
|
||||
[
|
||||
managedInstanceSubscriptionDropdownLabel,
|
||||
this._managedInstanceSubscriptionDropdown,
|
||||
managedInstanceDropdownLabel,
|
||||
this._managedInstanceDropdown
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
|
||||
const form = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[
|
||||
{
|
||||
component: targetContainer
|
||||
}
|
||||
]
|
||||
);
|
||||
await view.initializeModel(form.component());
|
||||
}
|
||||
public async onPageEnter(): Promise<void> {
|
||||
this.populateSubscriptionDropdown();
|
||||
}
|
||||
public async onPageLeave(): Promise<void> {
|
||||
}
|
||||
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
|
||||
}
|
||||
|
||||
private async populateSubscriptionDropdown(): Promise<void> {
|
||||
if (!this.migrationStateModel._targetSubscription) {
|
||||
this._managedInstanceSubscriptionDropdown.loading = true;
|
||||
this._managedInstanceDropdown.loading = true;
|
||||
try {
|
||||
this._managedInstanceSubscriptionDropdown.values = await this.migrationStateModel.getSubscriptionsDropdownValues();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
} finally {
|
||||
this._managedInstanceSubscriptionDropdown.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async populateManagedInstanceDropdown(): Promise<void> {
|
||||
if (!this.migrationStateModel._targetServerInstance) {
|
||||
this._managedInstanceDropdown.loading = true;
|
||||
try {
|
||||
this._managedInstanceDropdown.values = await this.migrationStateModel.getManagedInstanceValues(this.migrationStateModel._targetSubscription);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
} finally {
|
||||
this._managedInstanceDropdown.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user