Migration Private preview 1 fixes 2 (#14898)

* Removing canary host

* Rebranding extension name to Azure SQL Migration

* stopping instance table overflow in assessment dialog

* Added info message for details copied

* Limiting storage account and DMS to the same subscription as target

* making accounts page look like figma mockups

* converting error messages to warnings in cutover dialog

* making source config page look like figma mockups

* adding more filters for storage account and dms

* Adding validations for target database names.

* Fixing branding in other strings

* Adding types for SQL Managed Instance
This commit is contained in:
Aasim Khan
2021-03-29 17:43:19 -07:00
committed by GitHub
parent 69361b5c97
commit a231d2aa82
20 changed files with 419 additions and 244 deletions

View File

@@ -35,6 +35,14 @@ export class AccountsSelectionPage extends MigrationWizardPage {
private createAzureAccountsDropdown(view: azdata.ModelView): azdata.FormComponent {
const azureAccountLabel = view.modelBuilder.text().withProps({
value: constants.ACCOUNTS_SELECTION_PAGE_TITLE,
requiredIndicator: true,
CSSStyles: {
'margin': '0px'
}
}).component();
this._azureAccountsDropdown = view.modelBuilder.dropDown()
.withProps({
width: WIZARD_INPUT_COMPONENT_WIDTH
@@ -101,7 +109,11 @@ export class AccountsSelectionPage extends MigrationWizardPage {
.withLayout({
flexFlow: 'column'
})
.withItems([this._azureAccountsDropdown, linkAccountButton])
.withItems([
azureAccountLabel,
this._azureAccountsDropdown,
linkAccountButton
])
.component();
return {
@@ -114,6 +126,7 @@ export class AccountsSelectionPage extends MigrationWizardPage {
const azureTenantDropdownLabel = view.modelBuilder.text().withProps({
value: constants.AZURE_TENANT,
requiredIndicator: true,
CSSStyles: {
'margin': '0px'
}

View File

@@ -7,32 +7,39 @@ import * as azdata from 'azdata';
import { EOL } from 'os';
import { getStorageAccountAccessKeys } from '../api/azure';
import { MigrationWizardPage } from '../models/migrationWizardPage';
import { MigrationStateModel, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
import { MigrationStateModel, MigrationTargetType, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
import * as constants from '../constants/strings';
import * as vscode from 'vscode';
import { IconPathHelper } from '../constants/iconPathHelper';
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
export class DatabaseBackupPage extends MigrationWizardPage {
private _view!: azdata.ModelView;
private _networkShareContainer!: azdata.FlexContainer;
private _networkShareContainerSubscriptionDropdown!: azdata.DropDownComponent;
private _networkShareContainerSubscription!: azdata.InputBoxComponent;
private _networkShareContainerLocation!: azdata.InputBoxComponent;
private _networkShareStorageAccountResourceGroupDropdown!: azdata.DropDownComponent;
private _networkShareContainerStorageAccountDropdown!: azdata.DropDownComponent;
private _networkShareContainerStorageAccountRefreshButton!: azdata.ButtonComponent;
private _windowsUserAccountText!: azdata.InputBoxComponent;
private _passwordText!: azdata.InputBoxComponent;
private _networkShareDatabaseConfigContainer!: azdata.FlexContainer;
private _networkShareLocations: azdata.InputBoxComponent[] = [];
private _targetDatabaseNames: azdata.InputBoxComponent[] = [];
private _blobContainer!: azdata.FlexContainer;
private _blobContainerSubscriptionDropdown!: azdata.DropDownComponent;
private _blobContainerSubscription!: azdata.InputBoxComponent;
private _blobContainerStorageAccountDropdown!: azdata.DropDownComponent;
private _blobContainerDatabaseConfigContainer!: azdata.FlexContainer;
private _blobContainerDropdowns: azdata.DropDownComponent[] = [];
private _fileShareContainer!: azdata.FlexContainer;
private _fileShareSubscriptionDropdown!: azdata.DropDownComponent;
private _fileShareSubscription!: azdata.InputBoxComponent;
private _fileShareStorageAccountDropdown!: azdata.DropDownComponent;
private _fileShareDatabaseConfigContainer!: azdata.FlexContainer;
private _fileShareDropdowns: azdata.DropDownComponent[] = [];
private _existingDatabases: string[] = [];
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
super(wizard, azdata.window.createWizardPage(constants.DATABASE_BACKUP_PAGE_TITLE), migrationStateModel);
this.wizardPage.description = constants.DATABASE_BACKUP_PAGE_DESCRIPTION;
@@ -131,16 +138,10 @@ export class DatabaseBackupPage extends MigrationWizardPage {
value: constants.DATABASE_BACKUP_FILE_SHARE_SUBSCRIPTION_LABEL,
requiredIndicator: true,
}).component();
this._fileShareSubscriptionDropdown = view.modelBuilder.dropDown().withProps({
this._fileShareSubscription = view.modelBuilder.inputBox().withProps({
required: true,
enabled: false
}).component();
this._fileShareSubscriptionDropdown.onValueChanged(async (value) => {
if (value.selected) {
this.migrationStateModel._databaseBackup.subscription = this.migrationStateModel.getSubscription(value.index);
this.migrationStateModel._databaseBackup.storageAccount = undefined!;
await this.loadFileShareStorageDropdown();
}
});
const storageAccountLabel = view.modelBuilder.text()
.withProps({
@@ -159,7 +160,6 @@ export class DatabaseBackupPage extends MigrationWizardPage {
}
});
const fileShareDatabaseConfigHeader = view.modelBuilder.text().withProps({
value: constants.ENTER_FILE_SHARE_INFORMATION
}).component();
@@ -172,7 +172,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
.withItems(
[
subscriptionLabel,
this._fileShareSubscriptionDropdown,
this._fileShareSubscription,
storageAccountLabel,
this._fileShareStorageAccountDropdown,
fileShareDatabaseConfigHeader,
@@ -193,17 +193,11 @@ export class DatabaseBackupPage extends MigrationWizardPage {
value: constants.DATABASE_BACKUP_BLOB_STORAGE_SUBSCRIPTION_LABEL,
requiredIndicator: true,
}).component();
this._blobContainerSubscriptionDropdown = view.modelBuilder.dropDown()
this._blobContainerSubscription = view.modelBuilder.inputBox()
.withProps({
required: true
required: true,
enabled: false
}).component();
this._blobContainerSubscriptionDropdown.onValueChanged(async (value) => {
if (value.selected) {
this.migrationStateModel._databaseBackup.subscription = this.migrationStateModel.getSubscription(value.index);
this.migrationStateModel._databaseBackup.storageAccount = undefined!;
await this.loadblobStorageDropdown();
}
});
const storageAccountLabel = view.modelBuilder.text()
.withProps({
@@ -235,7 +229,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
.withItems(
[
subscriptionLabel,
this._blobContainerSubscriptionDropdown,
this._blobContainerSubscription,
storageAccountLabel,
this._blobContainerStorageAccountDropdown,
blobContainerDatabaseConfigHeader,
@@ -251,21 +245,61 @@ export class DatabaseBackupPage extends MigrationWizardPage {
}
private createNetworkShareContainer(view: azdata.ModelView): azdata.FlexContainer {
const networkShareHelpText = view.modelBuilder.text()
.withProps({
value: constants.DATABASE_BACKUP_NC_NETWORK_SHARE_HELP_TEXT,
}).component();
const networkShareHeading = view.modelBuilder.text().withProps({
value: constants.DATABASE_BACKUP_NETWORK_SHARE_HEADER_TEXT,
width: WIZARD_INPUT_COMPONENT_WIDTH,
CSSStyles: {
'font-size': '14px',
'font-weight': 'bold'
}
}).component();
const networkShareHelpText = view.modelBuilder.text().withProps({
value: constants.DATABASE_BACKUP_NC_NETWORK_SHARE_HELP_TEXT,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const networkLocationInputBoxLabel = this._view.modelBuilder.text().withProps({
value: constants.DATABASE_BACKUP_NETWORK_SHARE_LOCATION_LABEL,
requiredIndicator: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const networkLocationInputBox = this._view.modelBuilder.inputBox().withProps({
placeHolder: '\\\\Servername.domainname.com\\Backupfolder',
required: true,
validationErrorMessage: constants.INVALID_NETWORK_SHARE_LOCATION,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).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 networkShareInfoBox = view.modelBuilder.infoBox().withProps({
text: constants.DATABASE_SERVICE_ACCOUNT_INFO_TEXT,
style: 'information',
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const windowsUserAccountLabel = view.modelBuilder.text()
.withProps({
value: constants.DATABASE_BACKUP_NETWORK_SHARE_WINDOWS_USER_LABEL,
requiredIndicator: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._windowsUserAccountText = view.modelBuilder.inputBox()
.withProps({
placeHolder: 'Domain\\username',
required: true,
validationErrorMessage: constants.INVALID_USER_ACCOUNT
validationErrorMessage: constants.INVALID_USER_ACCOUNT,
width: WIZARD_INPUT_COMPONENT_WIDTH
})
.withValidation((component) => {
if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
@@ -285,98 +319,144 @@ export class DatabaseBackupPage extends MigrationWizardPage {
.withProps({
value: constants.DATABASE_BACKUP_NETWORK_SHARE_PASSWORD_LABEL,
requiredIndicator: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._passwordText = view.modelBuilder.inputBox()
.withProps({
placeHolder: constants.DATABASE_BACKUP_NETWORK_SHARE_PASSWORD_PLACEHOLDER,
inputType: 'password',
required: true
required: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._passwordText.onTextChanged((value) => {
this.migrationStateModel._databaseBackup.password = value;
});
const azureAccountHeader = view.modelBuilder.text()
.withProps({
value: constants.DATABASE_BACKUP_NETWORK_SHARE_AZURE_ACCOUNT_HEADER,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const azureAccountHelpText = view.modelBuilder.text()
.withProps({
value: constants.DATABASE_BACKUP_NETWORK_SHARE_AZURE_ACCOUNT_HELP,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const subscriptionLabel = view.modelBuilder.text()
.withProps({
value: constants.DATABASE_BACKUP_NETWORK_SHARE_SUBSCRIPTION_LABEL,
value: constants.SUBSCRIPTION,
requiredIndicator: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._networkShareContainerSubscriptionDropdown = view.modelBuilder.dropDown()
this._networkShareContainerSubscription = view.modelBuilder.inputBox()
.withProps({
required: true
required: true,
enabled: false,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._networkShareContainerSubscriptionDropdown.onValueChanged(async (value) => {
if (value.selected) {
this.migrationStateModel._databaseBackup.subscription = this.migrationStateModel.getSubscription(value.index);
this.migrationStateModel._databaseBackup.storageAccount = undefined!;
await this.loadNetworkShareStorageDropdown();
const locationLabel = view.modelBuilder.text()
.withProps({
value: constants.LOCATION,
requiredIndicator: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._networkShareContainerLocation = view.modelBuilder.inputBox()
.withProps({
required: true,
enabled: false,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const resourceGroupLabel = view.modelBuilder.text()
.withProps({
value: constants.RESOURCE_GROUP,
requiredIndicator: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._networkShareStorageAccountResourceGroupDropdown = view.modelBuilder.dropDown().withProps({
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._networkShareStorageAccountResourceGroupDropdown.onValueChanged(e => {
if (e.selected) {
this.migrationStateModel._databaseBackup.resourceGroup = this.migrationStateModel.getAzureResourceGroup(e.index);
this.loadNetworkShareStorageDropdown();
}
});
const storageAccountLabel = view.modelBuilder.text()
.withProps({
value: constants.DATABASE_BACKUP_NETWORK_SHARE_NETWORK_STORAGE_ACCOUNT_LABEL,
value: constants.STORAGE_ACCOUNT,
requiredIndicator: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._networkShareContainerStorageAccountDropdown = view.modelBuilder.dropDown()
.withProps({
required: true
required: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._networkShareContainerStorageAccountDropdown.onValueChanged((value) => {
if (value.selected) {
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
this._networkShareContainerStorageAccountRefreshButton = view.modelBuilder.button().withProps({
iconPath: IconPathHelper.refresh,
iconHeight: 18,
iconWidth: 18,
height: 25
}).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;
}
}
this._networkShareContainerStorageAccountRefreshButton.onDidClick((e) => {
this.loadNetworkShareStorageDropdown();
});
const storageAccountContainer = view.modelBuilder.flexContainer().component();
storageAccountContainer.addItem(this._networkShareContainerStorageAccountDropdown, {
flex: '0 0 auto'
});
storageAccountContainer.addItem(this._networkShareContainerStorageAccountRefreshButton, {
flex: '0 0 auto',
CSSStyles: {
'margin-left': '5px'
}
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
value: constants.ENTER_NETWORK_SHARE_INFORMATION,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._networkShareDatabaseConfigContainer = view.modelBuilder.flexContainer().withLayout({
flexFlow: 'column'
flexFlow: 'column',
}).component();
const flexContainer = view.modelBuilder.flexContainer().withItems(
[
azureAccountHelpText,
networkShareHeading,
networkShareHelpText,
networkLocationInputBoxLabel,
networkLocationInputBox,
networkShareInfoBox,
windowsUserAccountLabel,
this._windowsUserAccountText,
passwordLabel,
this._passwordText,
azureAccountHeader,
azureAccountHelpText,
subscriptionLabel,
this._networkShareContainerSubscriptionDropdown,
this._networkShareContainerSubscription,
locationLabel,
this._networkShareContainerLocation,
resourceGroupLabel,
this._networkShareStorageAccountResourceGroupDropdown,
storageAccountLabel,
this._networkShareContainerStorageAccountDropdown,
storageAccountContainer,
networkShareDatabaseConfigHeader,
this._networkShareDatabaseConfigContainer
]
@@ -391,8 +471,10 @@ export class DatabaseBackupPage extends MigrationWizardPage {
public async onPageEnter(): Promise<void> {
if (this.migrationStateModel.refreshDatabaseBackupPage) {
this._networkShareLocations = [];
this._targetDatabaseNames = [];
if (this.migrationStateModel._targetType === MigrationTargetType.SQLMI) {
this._existingDatabases = await this.migrationStateModel.getManagedDatabases();
}
this._fileShareDropdowns = [];
this._blobContainerDropdowns = [];
this.migrationStateModel._targetDatabaseNames = [];
@@ -411,11 +493,24 @@ export class DatabaseBackupPage extends MigrationWizardPage {
}).component();
const targetNameNetworkInputBox = this._view.modelBuilder.inputBox().withProps({
required: true,
value: db
value: db,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).withValidation(c => {
if (this._targetDatabaseNames.filter(t => t.value === c.value).length > 1) { //Making sure no databases have duplicate values.
c.validationErrorMessage = constants.DUPLICATE_NAME_ERROR;
return false;
}
if (this.migrationStateModel._targetType === MigrationTargetType.SQLMI && this._existingDatabases.includes(c.value!)) { // Making sure if database with same name is not present on the target Azure SQL
c.validationErrorMessage = constants.DATABASE_ALREADY_EXISTS_MI(this.migrationStateModel._targetServerInstance.name);
return false;
}
return true;
}).component();
targetNameNetworkInputBox.onTextChanged((value) => {
this.migrationStateModel._targetDatabaseNames[index] = value;
});
this._targetDatabaseNames.push(targetNameNetworkInputBox);
this._networkShareDatabaseConfigContainer.addItems(
[
targetNameNetworkInputBoxLabel,
@@ -437,7 +532,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
.withProps({
}).component();
fileShareDropdown.onValueChanged((value) => {
if (value.selected) {
if (value.selected && value.selected !== constants.NO_FILESHARES_FOUND) {
this.validateFields();
this.migrationStateModel._databaseBackup.fileShares[index] = this.migrationStateModel.getFileShare(value.index);
}
@@ -467,7 +562,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
.withProps({
}).component();
blobContainerDropdown.onValueChanged((value) => {
if (value.selected) {
if (value.selected && value.selected !== constants.NO_BLOBCONTAINERS_FOUND) {
this.validateFields();
this.migrationStateModel._databaseBackup.blobContainers[index] = this.migrationStateModel.getBlobContainer(value.index);
}
@@ -496,7 +591,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
switch (this.migrationStateModel._databaseBackup.networkContainerType) {
case NetworkContainerType.NETWORK_SHARE:
if ((<azdata.CategoryValue>this._networkShareContainerSubscriptionDropdown.value).displayName === constants.NO_SUBSCRIPTIONS_FOUND) {
if (this._networkShareContainerSubscription.value === constants.NO_SUBSCRIPTIONS_FOUND) {
errors.push(constants.INVALID_SUBSCRIPTION_ERROR);
}
if ((<azdata.CategoryValue>this._networkShareContainerStorageAccountDropdown.value).displayName === constants.NO_STORAGE_ACCOUNT_FOUND) {
@@ -504,9 +599,6 @@ export class DatabaseBackupPage extends MigrationWizardPage {
}
break;
case NetworkContainerType.BLOB_CONTAINER:
if ((<azdata.CategoryValue>this._blobContainerSubscriptionDropdown.value).displayName === constants.NO_SUBSCRIPTIONS_FOUND) {
errors.push(constants.INVALID_SUBSCRIPTION_ERROR);
}
if ((<azdata.CategoryValue>this._blobContainerStorageAccountDropdown.value).displayName === constants.NO_STORAGE_ACCOUNT_FOUND) {
errors.push(constants.INVALID_STORAGE_ACCOUNT_ERROR);
}
@@ -518,9 +610,6 @@ export class DatabaseBackupPage extends MigrationWizardPage {
}
break;
case NetworkContainerType.FILE_SHARE:
if ((<azdata.CategoryValue>this._fileShareSubscriptionDropdown.value).displayName === constants.NO_SUBSCRIPTIONS_FOUND) {
errors.push(constants.INVALID_SUBSCRIPTION_ERROR);
}
if ((<azdata.CategoryValue>this._fileShareStorageAccountDropdown.value).displayName === constants.NO_STORAGE_ACCOUNT_FOUND) {
errors.push(constants.INVALID_STORAGE_ACCOUNT_ERROR);
}
@@ -545,10 +634,13 @@ export class DatabaseBackupPage extends MigrationWizardPage {
}
public async onPageLeave(): Promise<void> {
this.migrationStateModel._databaseBackup.storageKey = (await getStorageAccountAccessKeys(this.migrationStateModel._azureAccount, this.migrationStateModel._databaseBackup.subscription, this.migrationStateModel._databaseBackup.storageAccount)).keyName1;
this.wizard.registerNavigationValidator((pageChangeInfo) => {
return true;
});
try {
this.migrationStateModel._databaseBackup.storageKey = (await getStorageAccountAccessKeys(this.migrationStateModel._azureAccount, this.migrationStateModel._databaseBackup.subscription, this.migrationStateModel._databaseBackup.storageAccount)).keyName1;
} finally {
this.wizard.registerNavigationValidator((pageChangeInfo) => {
return true;
});
}
}
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
@@ -559,30 +651,25 @@ export class DatabaseBackupPage extends MigrationWizardPage {
this._fileShareContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.FILE_SHARE) ? 'inline' : 'none' });
this._blobContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.BLOB_CONTAINER) ? 'inline' : 'none' });
this._networkShareContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none' });
this._networkShareLocations.forEach((inputBox) => {
inputBox.updateProperties({
required: containerType === NetworkContainerType.NETWORK_SHARE
});
});
this._windowsUserAccountText.updateProperties({
required: containerType === NetworkContainerType.NETWORK_SHARE
});
this._passwordText.updateProperties({
required: containerType === NetworkContainerType.NETWORK_SHARE
});
this._networkShareLocations.forEach((inputBox) => {
this._targetDatabaseNames.forEach((inputBox) => {
inputBox.validate();
});
this._windowsUserAccountText.validate();
this._passwordText.validate();
this._networkShareContainerSubscriptionDropdown.validate();
this._networkShareContainerSubscription.validate();
this._networkShareContainerStorageAccountDropdown.validate();
this._blobContainerSubscriptionDropdown.validate();
this._blobContainerSubscription.validate();
this._blobContainerStorageAccountDropdown.validate();
this._blobContainerDropdowns.forEach((dropdown) => {
dropdown.validate();
});
this._fileShareSubscriptionDropdown.validate();
this._fileShareSubscription.validate();
this._fileShareStorageAccountDropdown.validate();
this._fileShareDropdowns.forEach(dropdown => {
dropdown.validate();
@@ -592,19 +679,19 @@ export class DatabaseBackupPage extends MigrationWizardPage {
private validateFields(): void {
this._networkShareLocations.forEach((inputBox) => {
this._targetDatabaseNames.forEach((inputBox) => {
inputBox.validate();
});
this._windowsUserAccountText.validate();
this._passwordText.validate();
this._networkShareContainerSubscriptionDropdown.validate();
this._networkShareContainerSubscription.validate();
this._networkShareContainerStorageAccountDropdown.validate();
this._blobContainerSubscriptionDropdown.validate();
this._blobContainerSubscription.validate();
this._blobContainerStorageAccountDropdown.validate();
this._blobContainerDropdowns.forEach((dropdown) => {
dropdown.validate();
});
this._fileShareSubscriptionDropdown.validate();
this._fileShareSubscription.validate();
this._fileShareStorageAccountDropdown.validate();
this._fileShareDropdowns.forEach((dropdown) => {
dropdown.validate();
@@ -612,35 +699,36 @@ export class DatabaseBackupPage extends MigrationWizardPage {
}
private async getSubscriptionValues(): Promise<void> {
if (!this.migrationStateModel._databaseBackup.subscription) {
this._networkShareContainerSubscriptionDropdown.loading = true;
this._fileShareSubscriptionDropdown.loading = true;
this._blobContainerSubscriptionDropdown.loading = true;
try {
const subscriptionDropdownValues = await this.migrationStateModel.getSubscriptionsDropdownValues();
this._fileShareSubscriptionDropdown.values = subscriptionDropdownValues;
this._networkShareContainerSubscriptionDropdown.values = subscriptionDropdownValues;
this._blobContainerSubscriptionDropdown.values = subscriptionDropdownValues;
} catch (error) {
console.log(error);
} finally {
this._networkShareContainerSubscriptionDropdown.loading = false;
this._fileShareSubscriptionDropdown.loading = false;
this._blobContainerSubscriptionDropdown.loading = false;
}
this._fileShareSubscription.value = this.migrationStateModel._targetSubscription.name;
this._networkShareContainerSubscription.value = this.migrationStateModel._targetSubscription.name;
this._networkShareContainerLocation.value = await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.location);
this._blobContainerSubscription.value = this.migrationStateModel._targetSubscription.name;
this.migrationStateModel._databaseBackup.subscription = this.migrationStateModel._targetSubscription;
this.loadNetworkStorageResourceGroup();
this.loadFileShareStorageDropdown();
this.loadblobStorageDropdown();
}
private async loadNetworkStorageResourceGroup(): Promise<void> {
this._networkShareStorageAccountResourceGroupDropdown.loading = true;
try {
this._networkShareStorageAccountResourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._databaseBackup.subscription);
} catch (error) {
console.log(error);
} finally {
this._networkShareStorageAccountResourceGroupDropdown.loading = false;
this.loadNetworkShareStorageDropdown();
}
}
private async loadNetworkShareStorageDropdown(): Promise<void> {
if (!this.migrationStateModel._databaseBackup.storageAccount) {
this._networkShareContainerStorageAccountDropdown.loading = true;
try {
this._networkShareContainerStorageAccountDropdown.values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel._databaseBackup.subscription);
} catch (error) {
console.log(error);
} finally {
this._networkShareContainerStorageAccountDropdown.loading = false;
}
this._networkShareContainerStorageAccountDropdown.loading = true;
try {
this._networkShareContainerStorageAccountDropdown.values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel._databaseBackup.subscription);
} catch (error) {
console.log(error);
} finally {
this._networkShareContainerStorageAccountDropdown.loading = false;
}
}

View File

@@ -410,7 +410,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
migrationServiceTitle,
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name),
createInformationRow(this._view, constants.RESOURCE_GROUP, migrationService.properties.resourceGroup),
createInformationRow(this._view, constants.LOCATION, migrationService.properties.location),
createInformationRow(this._view, constants.LOCATION, await this.migrationStateModel.getLocationDisplayName(migrationService.properties.location)),
connectionLabelContainer,
connectionStatusLoader,
authenticationKeysLabel,

View File

@@ -11,6 +11,7 @@ import * as constants from '../constants/strings';
import * as vscode from 'vscode';
import { EOL } from 'os';
import { IconPath, IconPathHelper } from '../constants/iconPathHelper';
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
export interface Product {
type: MigrationTargetType;
@@ -60,9 +61,12 @@ export class SKURecommendationPage extends MigrationWizardPage {
const managedInstanceSubscriptionDropdownLabel = view.modelBuilder.text().withProps({
value: constants.SUBSCRIPTION
value: constants.SUBSCRIPTION,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._managedInstanceSubscriptionDropdown = view.modelBuilder.dropDown().withProps({
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._managedInstanceSubscriptionDropdown = view.modelBuilder.dropDown().component();
this._managedInstanceSubscriptionDropdown.onValueChanged((e) => {
if (e.selected) {
this.migrationStateModel._targetSubscription = this.migrationStateModel.getSubscription(e.index);
@@ -72,13 +76,17 @@ export class SKURecommendationPage extends MigrationWizardPage {
}
});
this._resourceDropdownLabel = view.modelBuilder.text().withProps({
value: constants.MANAGED_INSTANCE
value: constants.MANAGED_INSTANCE,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const azureLocationLabel = view.modelBuilder.text().withProps({
value: constants.LOCATION
value: constants.LOCATION,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._azureLocationDropdown = view.modelBuilder.dropDown().withProps({
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._azureLocationDropdown = view.modelBuilder.dropDown().component();
this._azureLocationDropdown.onValueChanged((e) => {
if (e.selected) {
this.migrationStateModel._location = this.migrationStateModel.getLocation(e.index);
@@ -86,14 +94,18 @@ export class SKURecommendationPage extends MigrationWizardPage {
}
});
this._resourceDropdownLabel = view.modelBuilder.text().withProps({
value: constants.MANAGED_INSTANCE
value: constants.MANAGED_INSTANCE,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const azureResourceGroupLabel = view.modelBuilder.text().withProps({
value: constants.RESOURCE_GROUP
value: constants.RESOURCE_GROUP,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._azureResourceGroupDropdown = view.modelBuilder.dropDown().withProps({
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._azureResourceGroupDropdown = view.modelBuilder.dropDown().component();
this._azureResourceGroupDropdown.onValueChanged((e) => {
if (e.selected) {
this.migrationStateModel._resourceGroup = this.migrationStateModel.getAzureResourceGroup(e.index);
@@ -101,10 +113,13 @@ export class SKURecommendationPage extends MigrationWizardPage {
}
});
this._resourceDropdownLabel = view.modelBuilder.text().withProps({
value: constants.MANAGED_INSTANCE
value: constants.MANAGED_INSTANCE,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._resourceDropdown = view.modelBuilder.dropDown().component();
this._resourceDropdown = view.modelBuilder.dropDown().withProps({
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._resourceDropdown.onValueChanged((e) => {
if (e.selected &&
e.selected !== constants.NO_MANAGED_INSTANCE_FOUND &&
@@ -272,9 +287,11 @@ export class SKURecommendationPage extends MigrationWizardPage {
private changeTargetType(newTargetType: string) {
if (newTargetType === MigrationTargetType.SQLMI) {
this.migrationStateModel._targetType = MigrationTargetType.SQLMI;
this._azureSubscriptionText.value = constants.SELECT_AZURE_MI;
this.migrationStateModel._migrationDbs = this.migrationStateModel._miDbs;
} else {
this.migrationStateModel._targetType = MigrationTargetType.SQLVM;
this._azureSubscriptionText.value = constants.SELECT_AZURE_VM;
this.migrationStateModel._migrationDbs = this.migrationStateModel._vmDbs;
}

View File

@@ -8,7 +8,7 @@ import * as os from 'os';
import { MigrationWizardPage } from '../models/migrationWizardPage';
import { MigrationSourceAuthenticationType, MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
import * as constants from '../constants/strings';
import { createLabelTextComponent, createHeadingTextComponent } from './wizardController';
import { createLabelTextComponent, createHeadingTextComponent, WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
export class SqlSourceConfigurationPage extends MigrationWizardPage {
private _view!: azdata.ModelView;
@@ -70,29 +70,46 @@ export class SqlSourceConfigurationPage extends MigrationWizardPage {
const enterYourCredText = createLabelTextComponent(
this._view,
constants.ENTER_YOUR_SQL_CREDS(connectionProfile.serverName),
constants.ENTER_YOUR_SQL_CREDS,
{
'width': '400px'
'width': '600px'
}
);
const serverLabel = this._view.modelBuilder.text().withProps({
value: constants.SERVER,
requiredIndicator: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const server = this._view.modelBuilder.inputBox().withProps({
value: connectionProfile.serverName,
enabled: false,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const authenticationTypeLable = this._view.modelBuilder.text().withProps({
value: constants.AUTHENTICATION_TYPE
value: constants.AUTHENTICATION_TYPE,
requiredIndicator: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const authenticationTypeInput = this._view.modelBuilder.inputBox().withProps({
value: this.migrationStateModel._authenticationType === MigrationSourceAuthenticationType.Sql ? 'SQL Login' : 'Windows Authentication',
enabled: false
enabled: false,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
const usernameLable = this._view.modelBuilder.text().withProps({
value: constants.USERNAME,
requiredIndicator: true
requiredIndicator: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._usernameInput = this._view.modelBuilder.inputBox().withProps({
value: username,
required: true,
enabled: false
enabled: false,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._usernameInput.onTextChanged(value => {
this.migrationStateModel._sqlServerUsername = value;
@@ -100,12 +117,14 @@ export class SqlSourceConfigurationPage extends MigrationWizardPage {
const passwordLabel = this._view.modelBuilder.text().withProps({
value: constants.DATABASE_BACKUP_NETWORK_SHARE_PASSWORD_LABEL,
requiredIndicator: true
requiredIndicator: true,
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._password = this._view.modelBuilder.inputBox().withProps({
value: (await azdata.connection.getCredentials(this.migrationStateModel.sourceConnectionId)).password,
required: true,
inputType: 'password'
inputType: 'password',
width: WIZARD_INPUT_COMPONENT_WIDTH
}).component();
this._password.onTextChanged(value => {
this.migrationStateModel._sqlServerPassword = value;
@@ -115,6 +134,8 @@ export class SqlSourceConfigurationPage extends MigrationWizardPage {
[
sourceCredText,
enterYourCredText,
serverLabel,
server,
authenticationTypeLable,
authenticationTypeInput,
usernameLable,

View File

@@ -17,7 +17,7 @@ import { SummaryPage } from './summaryPage';
import { MigrationModePage } from './migrationModePage';
import { SqlSourceConfigurationPage } from './sqlSourceConfigurationPage';
export const WIZARD_INPUT_COMPONENT_WIDTH = '400px';
export const WIZARD_INPUT_COMPONENT_WIDTH = '600px';
export class WizardController {
constructor(private readonly extensionContext: vscode.ExtensionContext) {