mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-27 17:23:21 -05:00
Migration wizard Refresh 11th Feb 2021 (#14257)
* Adding summary page, Storing ongoing migrations, localizing some string, made changes to how dropdowns work updated database backup page * Moved classes into different files Fixed a lot of typos Fixed some UI margins
This commit is contained in:
@@ -8,13 +8,14 @@ import * as vscode from 'vscode';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../models/strings';
|
||||
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
||||
|
||||
export class AccountsSelectionPage extends MigrationWizardPage {
|
||||
private _azureAccountsDropdown!: azdata.DropDownComponent;
|
||||
private _accountsMap: Map<string, azdata.Account> = new Map();
|
||||
|
||||
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
|
||||
super(wizard, azdata.window.createWizardPage(constants.ACCOUNTS_SELECTION_PAGE_TITLE), migrationStateModel);
|
||||
this.wizardPage.description = constants.ACCOUNTS_SELECTION_PAGE_DESCRIPTION;
|
||||
}
|
||||
|
||||
protected async registerContent(view: azdata.ModelView): Promise<void> {
|
||||
@@ -30,32 +31,36 @@ export class AccountsSelectionPage extends MigrationWizardPage {
|
||||
|
||||
private createAzureAccountsDropdown(view: azdata.ModelView): azdata.FormComponent {
|
||||
|
||||
this._azureAccountsDropdown = view.modelBuilder.dropDown().withValidation((c) => {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR) {
|
||||
this.wizard.message = {
|
||||
text: constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR,
|
||||
level: azdata.window.MessageLevel.Error
|
||||
};
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
this._azureAccountsDropdown = view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH
|
||||
})
|
||||
.withValidation((c) => {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR) {
|
||||
this.wizard.message = {
|
||||
text: constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR,
|
||||
level: azdata.window.MessageLevel.Error
|
||||
};
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
|
||||
this._azureAccountsDropdown.onValueChanged(async (value) => {
|
||||
if (this._azureAccountsDropdown.value) {
|
||||
const selectedAccount = (this._azureAccountsDropdown.value as azdata.CategoryValue).name;
|
||||
this.migrationStateModel.azureAccount = this._accountsMap.get(selectedAccount)!;
|
||||
if (value.selected) {
|
||||
this.migrationStateModel.azureAccount = this.migrationStateModel.getAccount(value.index);
|
||||
this.migrationStateModel.subscriptions = undefined!;
|
||||
}
|
||||
});
|
||||
|
||||
const addAccountButton = view.modelBuilder.button()
|
||||
.withProperties<azdata.ButtonProperties>({
|
||||
label: constants.ACCOUNT_ADD_BUTTON_LABEL,
|
||||
width: '100px'
|
||||
const linkAccountButton = view.modelBuilder.hyperlink()
|
||||
.withProps({
|
||||
label: constants.ACCOUNT_LINK_BUTTON_LABEL,
|
||||
url: ''
|
||||
})
|
||||
.component();
|
||||
|
||||
addAccountButton.onDidClick(async (event) => {
|
||||
linkAccountButton.onDidClick(async (event) => {
|
||||
await vscode.commands.executeCommand('workbench.actions.modal.linkedAccount');
|
||||
await this.populateAzureAccountsDropdown();
|
||||
});
|
||||
@@ -64,7 +69,7 @@ export class AccountsSelectionPage extends MigrationWizardPage {
|
||||
.withLayout({
|
||||
flexFlow: 'column'
|
||||
})
|
||||
.withItems([this._azureAccountsDropdown, addAccountButton], { CSSStyles: { 'margin': '10px', } })
|
||||
.withItems([this._azureAccountsDropdown, linkAccountButton], { CSSStyles: { 'margin': '2px', } })
|
||||
.component();
|
||||
|
||||
return {
|
||||
@@ -75,27 +80,12 @@ export class AccountsSelectionPage extends MigrationWizardPage {
|
||||
|
||||
private async populateAzureAccountsDropdown(): Promise<void> {
|
||||
this._azureAccountsDropdown.loading = true;
|
||||
let accounts = await azdata.accounts.getAllAccounts();
|
||||
|
||||
if (accounts.length === 0) {
|
||||
this._azureAccountsDropdown.value = {
|
||||
displayName: constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR,
|
||||
name: ''
|
||||
};
|
||||
return;
|
||||
try {
|
||||
this._azureAccountsDropdown.values = await this.migrationStateModel.getAccountValues();
|
||||
this.migrationStateModel.azureAccount = this.migrationStateModel.getAccount(0);
|
||||
} finally {
|
||||
this._azureAccountsDropdown.loading = false;
|
||||
}
|
||||
|
||||
this._azureAccountsDropdown.values = accounts.map((account): azdata.CategoryValue => {
|
||||
let accountCategoryValue = {
|
||||
displayName: account.displayInfo.displayName,
|
||||
name: account.displayInfo.userId
|
||||
};
|
||||
this._accountsMap.set(accountCategoryValue.name, account);
|
||||
return accountCategoryValue;
|
||||
});
|
||||
|
||||
this.migrationStateModel.azureAccount = accounts[0];
|
||||
this._azureAccountsDropdown.loading = false;
|
||||
}
|
||||
|
||||
public async onPageEnter(): Promise<void> {
|
||||
|
||||
@@ -5,12 +5,13 @@
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { createMigrationController, getMigrationControllerRegions, getMigrationController, getResourceGroups, getSubscriptions, Subscription, getMigrationControllerAuthKeys } from '../api/azure';
|
||||
import { createMigrationController, getMigrationControllerRegions, getMigrationController, getResourceGroups, getMigrationControllerAuthKeys, getMigrationControllerMonitoringData } from '../api/azure';
|
||||
import { MigrationStateModel } from '../models/stateMachine';
|
||||
import * as constants from '../models/strings';
|
||||
import * as os from 'os';
|
||||
import { azureResource } from 'azureResource';
|
||||
import { IntergrationRuntimePage } from './integrationRuntimePage';
|
||||
import { IconPathHelper } from '../constants/iconPathHelper';
|
||||
|
||||
export class CreateMigrationControllerDialog {
|
||||
|
||||
@@ -22,17 +23,18 @@ export class CreateMigrationControllerDialog {
|
||||
|
||||
private _statusLoadingComponent!: azdata.LoadingComponent;
|
||||
private migrationControllerAuthKeyTable!: azdata.DeclarativeTableComponent;
|
||||
private _connectionStatus!: azdata.TextComponent;
|
||||
private _connectionStatus!: azdata.InfoBoxComponent;
|
||||
private _copyKey1Button!: azdata.ButtonComponent;
|
||||
private _copyKey2Button!: azdata.ButtonComponent;
|
||||
private _refreshKey1Button!: azdata.ButtonComponent;
|
||||
private _refreshKey2Button!: azdata.ButtonComponent;
|
||||
private _setupContainer!: azdata.FlexContainer;
|
||||
|
||||
private _dialogObject!: azdata.window.Dialog;
|
||||
private _view!: azdata.ModelView;
|
||||
private _subscriptionMap: Map<string, Subscription> = new Map();
|
||||
|
||||
constructor(private migrationStateModel: MigrationStateModel, private irPage: IntergrationRuntimePage) {
|
||||
this._dialogObject = azdata.window.createModelViewDialog(constants.IR_PAGE_TITLE, 'MigrationControllerDialog', 'wide');
|
||||
this._dialogObject = azdata.window.createModelViewDialog(constants.IR_PAGE_TITLE, 'MigrationControllerDialog', 'medium');
|
||||
}
|
||||
|
||||
initialize() {
|
||||
@@ -44,7 +46,7 @@ export class CreateMigrationControllerDialog {
|
||||
this._view = view;
|
||||
|
||||
this._formSubmitButton = view.modelBuilder.button().withProps({
|
||||
label: constants.SUBMIT,
|
||||
label: constants.CREATE,
|
||||
width: '80px'
|
||||
}).component();
|
||||
|
||||
@@ -52,7 +54,7 @@ export class CreateMigrationControllerDialog {
|
||||
this._statusLoadingComponent.loading = true;
|
||||
this._formSubmitButton.enabled = false;
|
||||
|
||||
const subscription = this._subscriptionMap.get((this.migrationControllerSubscriptionDropdown.value as azdata.CategoryValue).name)!;
|
||||
const subscription = this.migrationStateModel._targetSubscription;
|
||||
const resourceGroup = (this.migrationControllerResourceGroupDropdown.value as azdata.CategoryValue).name;
|
||||
const region = (this.migrationControllerRegionDropdown.value as azdata.CategoryValue).name;
|
||||
const controllerName = this.migrationControllerNameText.value;
|
||||
@@ -128,7 +130,7 @@ export class CreateMigrationControllerDialog {
|
||||
this._dialogObject.okButton.enabled = false;
|
||||
azdata.window.openDialog(this._dialogObject);
|
||||
this._dialogObject.cancelButton.onClick((e) => {
|
||||
this.migrationStateModel.migrationController = undefined;
|
||||
this.migrationStateModel.migrationController = undefined!;
|
||||
});
|
||||
this._dialogObject.okButton.onClick((e) => {
|
||||
this.irPage.populateMigrationController();
|
||||
@@ -155,7 +157,8 @@ export class CreateMigrationControllerDialog {
|
||||
}).component();
|
||||
|
||||
this.migrationControllerSubscriptionDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
required: true
|
||||
required: true,
|
||||
enabled: false
|
||||
}).component();
|
||||
|
||||
this.migrationControllerSubscriptionDropdown.onValueChanged((e) => {
|
||||
@@ -224,37 +227,21 @@ export class CreateMigrationControllerDialog {
|
||||
private async populateSubscriptions(): Promise<void> {
|
||||
this.migrationControllerSubscriptionDropdown.loading = true;
|
||||
this.migrationControllerResourceGroupDropdown.loading = true;
|
||||
const subscriptions = await getSubscriptions(this.migrationStateModel.azureAccount);
|
||||
|
||||
let subscriptionDropdownValues: azdata.CategoryValue[] = [];
|
||||
if (subscriptions && subscriptions.length > 0) {
|
||||
|
||||
subscriptions.forEach((subscription) => {
|
||||
this._subscriptionMap.set(subscription.id, subscription);
|
||||
subscriptionDropdownValues.push({
|
||||
name: subscription.id,
|
||||
displayName: subscription.name + ' - ' + subscription.id,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
} else {
|
||||
subscriptionDropdownValues = [
|
||||
{
|
||||
displayName: constants.NO_SUBSCRIPTIONS_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
this.migrationControllerSubscriptionDropdown.values = subscriptionDropdownValues;
|
||||
this.migrationControllerSubscriptionDropdown.values = [
|
||||
{
|
||||
displayName: this.migrationStateModel._targetSubscription.name,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
this.migrationControllerSubscriptionDropdown.loading = false;
|
||||
this.populateResourceGroups();
|
||||
}
|
||||
|
||||
private async populateResourceGroups(): Promise<void> {
|
||||
this.migrationControllerResourceGroupDropdown.loading = true;
|
||||
let subscription = this._subscriptionMap.get((this.migrationControllerSubscriptionDropdown.value as azdata.CategoryValue).name)!;
|
||||
let subscription = this.migrationStateModel._targetSubscription;
|
||||
const resourceGroups = await getResourceGroups(this.migrationStateModel.azureAccount, subscription);
|
||||
let resourceGroupDropdownValues: azdata.CategoryValue[] = [];
|
||||
if (resourceGroups && resourceGroups.length > 0) {
|
||||
@@ -278,79 +265,66 @@ export class CreateMigrationControllerDialog {
|
||||
|
||||
private createControllerStatus(): azdata.FlexContainer {
|
||||
|
||||
const informationTextBox = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_DIALOG_CONTROLLER_CONTAINER_DESCRIPTION
|
||||
}).component();
|
||||
|
||||
const expressSetupTitle = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_OPTION1_HEADING,
|
||||
const setupIRHeadingText = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_DIALOG_CONTROLLER_CONTAINER_HEADING,
|
||||
CSSStyles: {
|
||||
'font-weight': 'bold'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const expressSetupLink = this._view.modelBuilder.hyperlink().withProps({
|
||||
label: constants.CONTROLLER_OPTION1_SETUP_LINK_TEXT,
|
||||
url: ''
|
||||
const setupIRdescription = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_DIALOG_CONTROLLER_CONTAINER_DESCRIPTION,
|
||||
}).component();
|
||||
|
||||
expressSetupLink.onDidClick((e) => {
|
||||
vscode.window.showInformationMessage(constants.FEATURE_NOT_AVAILABLE);
|
||||
});
|
||||
const irSetupStep1Text = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_STEP1,
|
||||
links: [
|
||||
{
|
||||
text: constants.CONTROLLER_STEP1_LINK,
|
||||
url: 'https://www.microsoft.com/download/details.aspx?id=39717'
|
||||
}
|
||||
]
|
||||
}).component();
|
||||
|
||||
const manualSetupTitle = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_OPTION2_HEADING,
|
||||
const irSetupStep2Text = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_STEP2
|
||||
}).component();
|
||||
|
||||
const irSetupStep3Text = this._view.modelBuilder.hyperlink().withProps({
|
||||
label: constants.CONTROLLER_STEP3,
|
||||
url: '',
|
||||
CSSStyles: {
|
||||
'font-weight': 'bold'
|
||||
'margin-top': '10px',
|
||||
'margin-bottom': '10px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const manualSetupButton = this._view.modelBuilder.hyperlink().withProps({
|
||||
label: constants.CONTROLLER_OPTION2_STEP1,
|
||||
url: 'https://www.microsoft.com/download/details.aspx?id=39717'
|
||||
}).component();
|
||||
|
||||
const manualSetupSecondDescription = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_OPTION2_STEP2
|
||||
}).component();
|
||||
|
||||
const connectionStatusTitle = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_CONNECTION_STATUS,
|
||||
CSSStyles: {
|
||||
'font-weight': 'bold'
|
||||
}
|
||||
}).component();
|
||||
|
||||
this._connectionStatus = this._view.modelBuilder.text().withProps({
|
||||
value: ''
|
||||
}).component();
|
||||
|
||||
const refreshButton = this._view.modelBuilder.button().withProps({
|
||||
label: constants.REFRESH,
|
||||
secondary: true
|
||||
}).component();
|
||||
|
||||
const refreshLoadingIndicator = this._view.modelBuilder.loadingComponent().withProps({
|
||||
loading: false
|
||||
}).component();
|
||||
|
||||
refreshButton.onDidClick(async (e) => {
|
||||
irSetupStep3Text.onDidClick(async (e) => {
|
||||
refreshLoadingIndicator.loading = true;
|
||||
this._connectionStatus.updateCssStyles({
|
||||
'display': 'none'
|
||||
});
|
||||
try {
|
||||
await this.refreshStatus();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
this._connectionStatus.updateCssStyles({
|
||||
'display': 'inline'
|
||||
});
|
||||
refreshLoadingIndicator.loading = false;
|
||||
});
|
||||
|
||||
const connectionStatusContainer = this._view.modelBuilder.flexContainer().withItems(
|
||||
[
|
||||
this._connectionStatus,
|
||||
refreshButton,
|
||||
refreshLoadingIndicator
|
||||
]
|
||||
).component();
|
||||
|
||||
this._connectionStatus = this._view.modelBuilder.infoBox().component();
|
||||
|
||||
this._connectionStatus.CSSStyles = {
|
||||
'width': '350px'
|
||||
};
|
||||
|
||||
const refreshLoadingIndicator = this._view.modelBuilder.loadingComponent().withProps({
|
||||
loading: false
|
||||
}).component();
|
||||
|
||||
|
||||
this.migrationControllerAuthKeyTable = this._view.modelBuilder.declarativeTable().withProps({
|
||||
@@ -358,54 +332,54 @@ export class CreateMigrationControllerDialog {
|
||||
{
|
||||
displayName: constants.NAME,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '100px',
|
||||
width: '50px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
'text-align': 'center'
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: constants.AUTH_KEY_COLUMN_HEADER,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '300px',
|
||||
width: '500px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
overflow: 'scroll'
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '15px',
|
||||
isReadOnly: true,
|
||||
},
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '100px',
|
||||
width: '15px',
|
||||
isReadOnly: true,
|
||||
}
|
||||
],
|
||||
CSSStyles: {
|
||||
'margin-top': '25px'
|
||||
'margin-top': '5px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const refreshKeyButton = this._view.modelBuilder.button().withProps({
|
||||
label: constants.REFRESH_KEYS,
|
||||
CSSStyles: {
|
||||
'margin-top': '10px'
|
||||
},
|
||||
width: '100px',
|
||||
secondary: true
|
||||
}).component();
|
||||
|
||||
refreshKeyButton.onDidClick(async (e) => {
|
||||
this.refreshAuthTable();
|
||||
|
||||
});
|
||||
|
||||
this._setupContainer = this._view.modelBuilder.flexContainer().withItems(
|
||||
[
|
||||
informationTextBox,
|
||||
expressSetupTitle,
|
||||
expressSetupLink,
|
||||
manualSetupTitle,
|
||||
manualSetupButton,
|
||||
manualSetupSecondDescription,
|
||||
refreshKeyButton,
|
||||
setupIRHeadingText,
|
||||
setupIRdescription,
|
||||
irSetupStep1Text,
|
||||
irSetupStep2Text,
|
||||
this.migrationControllerAuthKeyTable,
|
||||
connectionStatusTitle,
|
||||
connectionStatusContainer
|
||||
]
|
||||
irSetupStep3Text,
|
||||
this._connectionStatus,
|
||||
refreshLoadingIndicator
|
||||
], {
|
||||
CSSStyles: {
|
||||
'margin-bottom': '5px'
|
||||
}
|
||||
}
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
@@ -415,32 +389,42 @@ export class CreateMigrationControllerDialog {
|
||||
}
|
||||
|
||||
private async refreshStatus(): Promise<void> {
|
||||
const subscription = this._subscriptionMap.get((this.migrationControllerSubscriptionDropdown.value as azdata.CategoryValue).name)!;
|
||||
const subscription = this.migrationStateModel._targetSubscription;
|
||||
const resourceGroup = (this.migrationControllerResourceGroupDropdown.value as azdata.CategoryValue).name;
|
||||
const region = (this.migrationControllerRegionDropdown.value as azdata.CategoryValue).name;
|
||||
const controllerStatus = await getMigrationController(this.migrationStateModel.azureAccount, subscription, resourceGroup, region, this.migrationStateModel.migrationController!.name);
|
||||
const controllerMonitoringStatus = await getMigrationControllerMonitoringData(this.migrationStateModel.azureAccount, subscription, resourceGroup, region, this.migrationStateModel.migrationController!.name);
|
||||
this.migrationStateModel._nodeNames = controllerMonitoringStatus.nodes.map((node) => {
|
||||
return node.nodeName;
|
||||
});
|
||||
if (controllerStatus) {
|
||||
const state = controllerStatus.properties.integrationRuntimeState;
|
||||
|
||||
if (state === 'Online') {
|
||||
this._connectionStatus.value = constants.CONTRLLER_READY(this.migrationStateModel.migrationController!.name, os.hostname());
|
||||
this._connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.CONTROLLER_READY(this.migrationStateModel.migrationController!.name, this.migrationStateModel._nodeNames.join(', ')),
|
||||
style: 'success'
|
||||
});
|
||||
this._dialogObject.okButton.enabled = true;
|
||||
} else {
|
||||
this._connectionStatus.value = constants.CONTRLLER_NOT_READY(this.migrationStateModel.migrationController!.name);
|
||||
this._connectionStatus.text = constants.CONTROLLER_NOT_READY(this.migrationStateModel.migrationController!.name);
|
||||
this._connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.CONTROLLER_NOT_READY(this.migrationStateModel.migrationController!.name),
|
||||
style: 'warning'
|
||||
});
|
||||
this._dialogObject.okButton.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private async refreshAuthTable(): Promise<void> {
|
||||
const subscription = this._subscriptionMap.get((this.migrationControllerSubscriptionDropdown.value as azdata.CategoryValue).name)!;
|
||||
const subscription = this.migrationStateModel._targetSubscription;
|
||||
const resourceGroup = (this.migrationControllerResourceGroupDropdown.value as azdata.CategoryValue).name;
|
||||
const region = (this.migrationControllerRegionDropdown.value as azdata.CategoryValue).name;
|
||||
const keys = await getMigrationControllerAuthKeys(this.migrationStateModel.azureAccount, subscription, resourceGroup, region, this.migrationStateModel.migrationController!.name);
|
||||
|
||||
this._copyKey1Button = this._view.modelBuilder.button().withProps({
|
||||
label: constants.COPY_KEY,
|
||||
secondary: true
|
||||
iconPath: IconPathHelper.copy
|
||||
}).component();
|
||||
|
||||
this._copyKey1Button.onDidClick((e) => {
|
||||
@@ -449,8 +433,7 @@ export class CreateMigrationControllerDialog {
|
||||
});
|
||||
|
||||
this._copyKey2Button = this._view.modelBuilder.button().withProps({
|
||||
label: constants.COPY_KEY,
|
||||
secondary: true
|
||||
iconPath: IconPathHelper.copy
|
||||
}).component();
|
||||
|
||||
this._copyKey2Button.onDidClick((e) => {
|
||||
@@ -458,28 +441,50 @@ export class CreateMigrationControllerDialog {
|
||||
vscode.window.showInformationMessage(constants.CONTROLLER_KEY_COPIED_HELP);
|
||||
});
|
||||
|
||||
this._refreshKey1Button = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.refresh
|
||||
}).component();
|
||||
|
||||
this._refreshKey1Button.onDidClick((e) => {
|
||||
this.refreshAuthTable();
|
||||
});
|
||||
|
||||
this._refreshKey2Button = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.refresh
|
||||
}).component();
|
||||
|
||||
this._refreshKey2Button.onDidClick((e) => {
|
||||
this.refreshAuthTable();
|
||||
});
|
||||
|
||||
this.migrationControllerAuthKeyTable.updateProperties({
|
||||
dataValues: [
|
||||
[
|
||||
{
|
||||
value: constants.CONTROLELR_KEY1_LABEL
|
||||
value: constants.CONTROLLER_KEY1_LABEL
|
||||
},
|
||||
{
|
||||
value: keys.keyName1
|
||||
},
|
||||
{
|
||||
value: this._copyKey1Button
|
||||
},
|
||||
{
|
||||
value: this._refreshKey1Button
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
value: constants.CONTROLELR_KEY2_LABEL
|
||||
value: constants.CONTROLLER_KEY2_LABEL
|
||||
},
|
||||
{
|
||||
value: keys.keyName2
|
||||
},
|
||||
{
|
||||
value: this._copyKey2Button
|
||||
},
|
||||
{
|
||||
value: this._refreshKey2Button
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -4,11 +4,10 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { azureResource } from 'azureResource';
|
||||
import { EOL } from 'os';
|
||||
import { getAvailableStorageAccounts, getBlobContainers, getFileShares, getSubscriptions, StorageAccount, Subscription } from '../api/azure';
|
||||
import { getStorageAccountAccessKeys } from '../api/azure';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { BlobContainer, FileShare, MigrationCutover, MigrationStateModel, NetworkContainerType, NetworkShare, StateChangeEvent } from '../models/stateMachine';
|
||||
import { MigrationCutover, MigrationStateModel, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../models/strings';
|
||||
|
||||
export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
@@ -30,14 +29,6 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
private _fileShareStorageAccountDropdown!: azdata.DropDownComponent;
|
||||
private _fileShareFileShareDropdown!: azdata.DropDownComponent;
|
||||
|
||||
private _networkShare = {} as NetworkShare;
|
||||
private _fileShare = {} as FileShare;
|
||||
private _blob = {} as BlobContainer;
|
||||
|
||||
private _subscriptionDropdownValues: azdata.CategoryValue[] = [];
|
||||
private _subscriptionMap: Map<string, Subscription> = new Map();
|
||||
private _storageAccountMap: Map<string, StorageAccount> = new Map();
|
||||
|
||||
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;
|
||||
@@ -65,12 +56,10 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
title: '',
|
||||
component: networkContainer
|
||||
},
|
||||
this.migrationCutoverContainer(view),
|
||||
this.emailNotificationContainer(view),
|
||||
this.migrationModeContainer(view),
|
||||
]
|
||||
);
|
||||
await view.initializeModel(form.component());
|
||||
this.toggleNetworkContainerFields(NetworkContainerType.NETWORK_SHARE, this._networkShare);
|
||||
}
|
||||
|
||||
private createBackupLocationComponent(view: azdata.ModelView): azdata.FormComponent {
|
||||
@@ -79,13 +68,12 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
const networkShareButton = view.modelBuilder.radioButton()
|
||||
.withProps({
|
||||
name: buttonGroup,
|
||||
label: constants.DATABASE_BACKUP_NC_NETWORK_SHARE_RADIO_LABEL,
|
||||
checked: true
|
||||
label: constants.DATABASE_BACKUP_NC_NETWORK_SHARE_RADIO_LABEL
|
||||
}).component();
|
||||
|
||||
networkShareButton.onDidChangeCheckedState((e) => {
|
||||
if (e) {
|
||||
this.toggleNetworkContainerFields(NetworkContainerType.NETWORK_SHARE, this._networkShare);
|
||||
this.toggleNetworkContainerFields(NetworkContainerType.NETWORK_SHARE);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -97,7 +85,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
|
||||
blobContainerButton.onDidChangeCheckedState((e) => {
|
||||
if (e) {
|
||||
this.toggleNetworkContainerFields(NetworkContainerType.BLOB_CONTAINER, this._blob);
|
||||
this.toggleNetworkContainerFields(NetworkContainerType.BLOB_CONTAINER);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -109,7 +97,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
|
||||
fileShareButton.onDidChangeCheckedState((e) => {
|
||||
if (e) {
|
||||
this.toggleNetworkContainerFields(NetworkContainerType.FILE_SHARE, this._fileShare);
|
||||
this.toggleNetworkContainerFields(NetworkContainerType.FILE_SHARE);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -139,8 +127,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
required: true,
|
||||
}).component();
|
||||
this._fileShareSubscriptionDropdown.onValueChanged(async (value) => {
|
||||
if (this._fileShareSubscriptionDropdown.value) {
|
||||
this._fileShare.subscriptionId = (this._fileShareSubscriptionDropdown.value as azdata.CategoryValue).name;
|
||||
if (value.selected) {
|
||||
this.migrationStateModel.databaseBackup.subscription = this.migrationStateModel.getSubscription(value.index);
|
||||
this.migrationStateModel._storageAccounts = undefined!;
|
||||
await this.loadFileShareStorageDropdown();
|
||||
}
|
||||
});
|
||||
@@ -155,8 +144,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
required: true
|
||||
}).component();
|
||||
this._fileShareStorageAccountDropdown.onValueChanged(async (value) => {
|
||||
if (this._fileShareStorageAccountDropdown.value) {
|
||||
this._fileShare.storageAccountId = (this._fileShareStorageAccountDropdown.value as azdata.CategoryValue).name;
|
||||
if (value.selected) {
|
||||
this.migrationStateModel.databaseBackup.storageAccount = this.migrationStateModel.getStorageAccount(value.index);
|
||||
this.migrationStateModel._fileShares = undefined!;
|
||||
await this.loadFileShareDropdown();
|
||||
}
|
||||
});
|
||||
@@ -171,8 +161,8 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
required: true
|
||||
}).component();
|
||||
this._fileShareFileShareDropdown.onValueChanged((value) => {
|
||||
if (this._fileShareFileShareDropdown.value) {
|
||||
this._fileShare.fileShareId = (this._fileShareFileShareDropdown.value as azdata.CategoryValue).name;
|
||||
if (value.selected) {
|
||||
this.migrationStateModel.databaseBackup.fileShare = this.migrationStateModel.getFileShare(value.index);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -189,6 +179,8 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).withProps({
|
||||
display: 'none'
|
||||
}).component();
|
||||
|
||||
return flexContainer;
|
||||
@@ -205,8 +197,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
required: true
|
||||
}).component();
|
||||
this._blobContainerSubscriptionDropdown.onValueChanged(async (value) => {
|
||||
if (this._blobContainerSubscriptionDropdown.value) {
|
||||
this._blob.subscriptionId = (this._blobContainerSubscriptionDropdown.value as azdata.CategoryValue).name;
|
||||
if (value.selected) {
|
||||
this.migrationStateModel.databaseBackup.subscription = this.migrationStateModel.getSubscription(value.index);
|
||||
this.migrationStateModel._storageAccounts = undefined!;
|
||||
await this.loadblobStorageDropdown();
|
||||
}
|
||||
});
|
||||
@@ -221,8 +214,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
required: true
|
||||
}).component();
|
||||
this._blobContainerStorageAccountDropdown.onValueChanged(async (value) => {
|
||||
if (this._blobContainerStorageAccountDropdown.value) {
|
||||
this._blob.storageAccountId = (this._blobContainerStorageAccountDropdown.value as azdata.CategoryValue).name;
|
||||
if (value.selected) {
|
||||
this.migrationStateModel.databaseBackup.storageAccount = this.migrationStateModel.getStorageAccount(value.index);
|
||||
this.migrationStateModel._blobContainers = undefined!;
|
||||
await this.loadBlobContainerDropdown();
|
||||
}
|
||||
});
|
||||
@@ -236,8 +230,8 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
required: true
|
||||
}).component();
|
||||
this._blobContainerBlobDropdown.onValueChanged((value) => {
|
||||
if (this._blobContainerBlobDropdown.value) {
|
||||
this._blob.containerId = (this._blobContainerBlobDropdown.value as azdata.CategoryValue).name;
|
||||
if (value.selected) {
|
||||
this.migrationStateModel.databaseBackup.blobContainer = this.migrationStateModel.getBlobContainer(value.index);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -253,6 +247,8 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).withProps({
|
||||
display: 'none'
|
||||
}).component();
|
||||
|
||||
return flexContainer;
|
||||
@@ -278,7 +274,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
.withValidation((component) => {
|
||||
if (this.migrationStateModel.databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
if (component.value) {
|
||||
if (!/^(\\)(\\[\w\.-_]+){2,}(\\?)$/.test(component.value)) {
|
||||
if (!/(?<=\\\\)[^\\]*/.test(component.value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -286,7 +282,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
return true;
|
||||
}).component();
|
||||
this._networkShareLocationText.onTextChanged((value) => {
|
||||
this._networkShare.networkShareLocation = value;
|
||||
this.migrationStateModel.databaseBackup.networkShareLocation = value;
|
||||
});
|
||||
|
||||
const windowsUserAccountLabel = view.modelBuilder.text()
|
||||
@@ -303,7 +299,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
.withValidation((component) => {
|
||||
if (this.migrationStateModel.databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
if (component.value) {
|
||||
if (!/^[a-zA-Z][a-zA-Z0-9\-\.]{0,61}[a-zA-Z]\\\w[\w\.\- ]*$/.test(component.value)) {
|
||||
if (!/(?<=\\).*$/.test(component.value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -311,7 +307,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
return true;
|
||||
}).component();
|
||||
this._windowsUserAccountText.onTextChanged((value) => {
|
||||
this._networkShare.windowsUser = value;
|
||||
this.migrationStateModel.databaseBackup.windowsUser = value;
|
||||
});
|
||||
|
||||
const passwordLabel = view.modelBuilder.text()
|
||||
@@ -326,7 +322,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
required: true
|
||||
}).component();
|
||||
this._passwordText.onTextChanged((value) => {
|
||||
this._networkShare.password = value;
|
||||
this.migrationStateModel.databaseBackup.password = value;
|
||||
});
|
||||
|
||||
const azureAccountHelpText = view.modelBuilder.text()
|
||||
@@ -344,8 +340,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
required: true
|
||||
}).component();
|
||||
this._networkShareContainerSubscriptionDropdown.onValueChanged(async (value) => {
|
||||
if (this._networkShareContainerSubscriptionDropdown.value) {
|
||||
this._networkShare.storageSubscriptionId = (this._networkShareContainerSubscriptionDropdown.value as azdata.CategoryValue).name;
|
||||
if (value.selected) {
|
||||
this.migrationStateModel.databaseBackup.subscription = this.migrationStateModel.getSubscription(value.index);
|
||||
this.migrationStateModel._storageAccounts = undefined!;
|
||||
await this.loadNetworkShareStorageDropdown();
|
||||
}
|
||||
});
|
||||
@@ -360,8 +357,8 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
required: true
|
||||
}).component();
|
||||
this._networkShareContainerStorageAccountDropdown.onValueChanged((value) => {
|
||||
if (this._networkShareContainerStorageAccountDropdown.value) {
|
||||
this._networkShare.storageAccountId = (this._networkShareContainerStorageAccountDropdown.value as azdata.CategoryValue).name;
|
||||
if (value.selected) {
|
||||
this.migrationStateModel.databaseBackup.storageAccount = this.migrationStateModel.getStorageAccount(value.index);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -382,72 +379,57 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).withProps({
|
||||
display: 'none'
|
||||
}).component();
|
||||
|
||||
return flexContainer;
|
||||
}
|
||||
|
||||
private emailNotificationContainer(view: azdata.ModelView): azdata.FormComponent {
|
||||
const emailCheckbox = view.modelBuilder.checkBox().withProps({
|
||||
label: constants.DATABASE_BACKUP_EMAIL_NOTIFICATION_CHECKBOX_LABEL
|
||||
}).component();
|
||||
|
||||
emailCheckbox.onChanged((value) => {
|
||||
if (value !== undefined) {
|
||||
this.migrationStateModel.databaseBackup.emailNotification = value;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
title: constants.DATABASE_BACKUP_EMAIL_NOTIFICATION_LABEL,
|
||||
component: emailCheckbox
|
||||
};
|
||||
}
|
||||
|
||||
private migrationCutoverContainer(view: azdata.ModelView): azdata.FormComponent {
|
||||
private migrationModeContainer(view: azdata.ModelView): azdata.FormComponent {
|
||||
const description = view.modelBuilder.text().withProps({
|
||||
value: constants.DATABASE_BACKUP_MIGRATION_CUTOVER_DESCRIPTION
|
||||
value: constants.DATABASE_BACKUP_MIGRATION_MODE_DESCRIPTION
|
||||
}).component();
|
||||
|
||||
const buttonGroup = 'cutoverContainer';
|
||||
|
||||
const automaticButton = view.modelBuilder.radioButton().withProps({
|
||||
label: constants.DATABASE_BACKUP_MIGRATION_CUTOVER_AUTOMATIC_LABEL,
|
||||
const onlineButton = view.modelBuilder.radioButton().withProps({
|
||||
label: constants.DATABASE_BACKUP_MIGRATION_MODE_ONLINE_LABEL,
|
||||
name: buttonGroup,
|
||||
checked: true
|
||||
}).component();
|
||||
|
||||
this.migrationStateModel.databaseBackup.migrationCutover = MigrationCutover.AUTOMATIC;
|
||||
this.migrationStateModel.databaseBackup.migrationCutover = MigrationCutover.ONLINE;
|
||||
|
||||
automaticButton.onDidChangeCheckedState((e) => {
|
||||
onlineButton.onDidChangeCheckedState((e) => {
|
||||
if (e) {
|
||||
this.migrationStateModel.databaseBackup.migrationCutover = MigrationCutover.AUTOMATIC;
|
||||
this.migrationStateModel.databaseBackup.migrationCutover = MigrationCutover.ONLINE;
|
||||
}
|
||||
});
|
||||
|
||||
const manualButton = view.modelBuilder.radioButton().withProps({
|
||||
label: constants.DATABASE_BACKUP_MIGRATION_CUTOVER_MANUAL_LABEL,
|
||||
const offlineButton = view.modelBuilder.radioButton().withProps({
|
||||
label: constants.DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_LABEL,
|
||||
name: buttonGroup
|
||||
}).component();
|
||||
|
||||
manualButton.onDidChangeCheckedState((e) => {
|
||||
offlineButton.onDidChangeCheckedState((e) => {
|
||||
if (e) {
|
||||
this.migrationStateModel.databaseBackup.migrationCutover = MigrationCutover.MANUAL;
|
||||
this.migrationStateModel.databaseBackup.migrationCutover = MigrationCutover.OFFLINE;
|
||||
}
|
||||
});
|
||||
|
||||
const flexContainer = view.modelBuilder.flexContainer().withItems(
|
||||
[
|
||||
description,
|
||||
automaticButton,
|
||||
manualButton
|
||||
onlineButton,
|
||||
offlineButton
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
|
||||
return {
|
||||
title: constants.DATABASE_BACKUP_MIGRATION_CUTOVER_LABEL,
|
||||
title: constants.DATABASE_BACKUP_MIGRATION_MODE_LABEL,
|
||||
component: flexContainer
|
||||
};
|
||||
}
|
||||
@@ -506,13 +488,14 @@ 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;
|
||||
console.log(this.migrationStateModel.databaseBackup);
|
||||
}
|
||||
|
||||
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
|
||||
}
|
||||
|
||||
private toggleNetworkContainerFields(containerType: NetworkContainerType, networkContainer: NetworkShare | BlobContainer | FileShare): void {
|
||||
this.migrationStateModel.databaseBackup.networkContainer = networkContainer;
|
||||
private toggleNetworkContainerFields(containerType: NetworkContainerType): void {
|
||||
this.migrationStateModel.databaseBackup.networkContainerType = containerType;
|
||||
this._fileShareContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.FILE_SHARE) ? 'inline' : 'none' });
|
||||
this._blobContainer.updateCssStyles({ 'display': (containerType === NetworkContainerType.BLOB_CONTAINER) ? 'inline' : 'none' });
|
||||
@@ -526,169 +509,105 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
this._passwordText.updateProperties({
|
||||
required: containerType === NetworkContainerType.NETWORK_SHARE
|
||||
});
|
||||
|
||||
this._networkShareLocationText.validate();
|
||||
this._windowsUserAccountText.validate();
|
||||
this._passwordText.validate();
|
||||
this._networkShareContainerSubscriptionDropdown.validate();
|
||||
this._networkShareContainerStorageAccountDropdown.validate();
|
||||
this._blobContainerSubscriptionDropdown.validate();
|
||||
this._blobContainerStorageAccountDropdown.validate();
|
||||
this._blobContainerBlobDropdown.validate();
|
||||
this._fileShareSubscriptionDropdown.validate();
|
||||
this._fileShareStorageAccountDropdown.validate();
|
||||
this._fileShareFileShareDropdown.validate();
|
||||
|
||||
}
|
||||
|
||||
private async getSubscriptionValues(): Promise<void> {
|
||||
this._networkShareContainerSubscriptionDropdown.loading = true;
|
||||
this._fileShareSubscriptionDropdown.loading = true;
|
||||
this._blobContainerSubscriptionDropdown.loading = true;
|
||||
|
||||
let subscriptions: azureResource.AzureResourceSubscription[] = [];
|
||||
|
||||
try {
|
||||
subscriptions = await getSubscriptions(this.migrationStateModel.azureAccount);
|
||||
subscriptions.forEach((subscription) => {
|
||||
this._subscriptionMap.set(subscription.id, subscription);
|
||||
this._subscriptionDropdownValues.push({
|
||||
name: subscription.id,
|
||||
displayName: subscription.name + ' - ' + subscription.id,
|
||||
});
|
||||
});
|
||||
|
||||
if (!this._subscriptionDropdownValues) {
|
||||
this._subscriptionDropdownValues = [
|
||||
{
|
||||
displayName: constants.NO_SUBSCRIPTIONS_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
this._fileShareSubscriptionDropdown.values = this._subscriptionDropdownValues;
|
||||
this._networkShareContainerSubscriptionDropdown.values = this._subscriptionDropdownValues;
|
||||
this._blobContainerSubscriptionDropdown.values = this._subscriptionDropdownValues;
|
||||
|
||||
this._networkShare.storageSubscriptionId = this._subscriptionDropdownValues[0].name;
|
||||
this._fileShare.subscriptionId = this._subscriptionDropdownValues[0].name;
|
||||
this._blob.subscriptionId = this._subscriptionDropdownValues[0].name;
|
||||
|
||||
this._fileShareSubscriptionDropdown.values = await this.migrationStateModel.getSubscriptionsDropdownValues();
|
||||
this._networkShareContainerSubscriptionDropdown.values = await this.migrationStateModel.getSubscriptionsDropdownValues();
|
||||
this._blobContainerSubscriptionDropdown.values = await this.migrationStateModel.getSubscriptionsDropdownValues();
|
||||
this.migrationStateModel.databaseBackup.subscription = this.migrationStateModel.getSubscription(0);
|
||||
} catch (error) {
|
||||
|
||||
console.log(error);
|
||||
this.setEmptyDropdownPlaceHolder(this._fileShareSubscriptionDropdown, constants.NO_SUBSCRIPTIONS_FOUND);
|
||||
this.setEmptyDropdownPlaceHolder(this._networkShareContainerSubscriptionDropdown, constants.NO_SUBSCRIPTIONS_FOUND);
|
||||
this.setEmptyDropdownPlaceHolder(this._blobContainerSubscriptionDropdown, constants.NO_SUBSCRIPTIONS_FOUND);
|
||||
this.migrationStateModel._storageAccounts = undefined!;
|
||||
} finally {
|
||||
await this.loadNetworkShareStorageDropdown();
|
||||
await this.loadFileShareStorageDropdown();
|
||||
await this.loadblobStorageDropdown();
|
||||
this._networkShareContainerSubscriptionDropdown.loading = false;
|
||||
this._fileShareSubscriptionDropdown.loading = false;
|
||||
this._blobContainerSubscriptionDropdown.loading = false;
|
||||
}
|
||||
|
||||
this._networkShareContainerSubscriptionDropdown.loading = false;
|
||||
this._fileShareSubscriptionDropdown.loading = false;
|
||||
this._blobContainerSubscriptionDropdown.loading = false;
|
||||
|
||||
await this.loadNetworkShareStorageDropdown();
|
||||
await this.loadFileShareStorageDropdown();
|
||||
await this.loadblobStorageDropdown();
|
||||
this._networkShareContainerSubscriptionDropdown.validate();
|
||||
this._networkShareContainerStorageAccountDropdown.validate();
|
||||
}
|
||||
|
||||
private async loadNetworkShareStorageDropdown(): Promise<void> {
|
||||
this._networkShareContainerStorageAccountDropdown.loading = true;
|
||||
|
||||
const subscriptionId = (<azdata.CategoryValue>this._networkShareContainerSubscriptionDropdown.value).name;
|
||||
if (!subscriptionId.length) {
|
||||
this.setEmptyDropdownPlaceHolder(this._networkShareContainerStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
} else {
|
||||
const storageAccounts = await this.loadStorageAccounts(this._networkShare.storageSubscriptionId);
|
||||
|
||||
if (storageAccounts && storageAccounts.length) {
|
||||
this._networkShareContainerStorageAccountDropdown.values = storageAccounts.map(s => <azdata.CategoryValue>{ name: s.id, displayName: s.name });
|
||||
this._networkShare.storageAccountId = storageAccounts[0].id;
|
||||
}
|
||||
else {
|
||||
this.setEmptyDropdownPlaceHolder(this._networkShareContainerStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
}
|
||||
try {
|
||||
this._networkShareContainerStorageAccountDropdown.values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel.databaseBackup.subscription);
|
||||
this.migrationStateModel.databaseBackup.storageAccount = this.migrationStateModel.getStorageAccount(0);
|
||||
} finally {
|
||||
this._networkShareContainerStorageAccountDropdown.loading = false;
|
||||
}
|
||||
this._networkShareContainerStorageAccountDropdown.loading = false;
|
||||
}
|
||||
|
||||
private async loadFileShareStorageDropdown(): Promise<void> {
|
||||
this._fileShareStorageAccountDropdown.loading = true;
|
||||
this._fileShareFileShareDropdown.loading = true;
|
||||
try {
|
||||
this._fileShareStorageAccountDropdown.values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel.databaseBackup.subscription);
|
||||
this.migrationStateModel.databaseBackup.storageAccount = this.migrationStateModel.getStorageAccount(0);
|
||||
} catch (error) {
|
||||
this.migrationStateModel._fileShares = undefined!;
|
||||
} finally {
|
||||
await this.loadFileShareDropdown();
|
||||
this._fileShareStorageAccountDropdown.loading = false;
|
||||
this._fileShareFileShareDropdown.loading = false;
|
||||
|
||||
const subscriptionId = (<azdata.CategoryValue>this._fileShareSubscriptionDropdown.value).name;
|
||||
if (!subscriptionId.length) {
|
||||
this.setEmptyDropdownPlaceHolder(this._fileShareStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
} else {
|
||||
const storageAccounts = await this.loadStorageAccounts(this._fileShare.subscriptionId);
|
||||
if (storageAccounts && storageAccounts.length) {
|
||||
this._fileShareStorageAccountDropdown.values = storageAccounts.map(s => <azdata.CategoryValue>{ name: s.id, displayName: s.name });
|
||||
this._fileShare.storageAccountId = storageAccounts[0].id;
|
||||
}
|
||||
else {
|
||||
this.setEmptyDropdownPlaceHolder(this._fileShareStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
this._fileShareStorageAccountDropdown.loading = false;
|
||||
}
|
||||
}
|
||||
this._fileShareStorageAccountDropdown.loading = false;
|
||||
await this.loadFileShareDropdown();
|
||||
}
|
||||
|
||||
private async loadblobStorageDropdown(): Promise<void> {
|
||||
this._blobContainerStorageAccountDropdown.loading = true;
|
||||
this._blobContainerBlobDropdown.loading = true;
|
||||
try {
|
||||
this._blobContainerStorageAccountDropdown.values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel.databaseBackup.subscription);
|
||||
this.migrationStateModel.databaseBackup.storageAccount = this.migrationStateModel.getStorageAccount(0);
|
||||
} catch (error) {
|
||||
this.migrationStateModel._blobContainers = undefined!;
|
||||
} finally {
|
||||
await this.loadBlobContainerDropdown();
|
||||
this._blobContainerStorageAccountDropdown.loading = false;
|
||||
this._blobContainerBlobDropdown.loading = true;
|
||||
|
||||
const subscriptionId = (<azdata.CategoryValue>this._blobContainerSubscriptionDropdown.value).name;
|
||||
if (!subscriptionId.length) {
|
||||
this.setEmptyDropdownPlaceHolder(this._blobContainerStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
} else {
|
||||
const storageAccounts = await this.loadStorageAccounts(this._blob.subscriptionId);
|
||||
if (storageAccounts.length) {
|
||||
this._blobContainerStorageAccountDropdown.values = storageAccounts.map(s => <azdata.CategoryValue>{ name: s.id, displayName: s.name });
|
||||
this._blob.storageAccountId = storageAccounts[0].id;
|
||||
} else {
|
||||
this.setEmptyDropdownPlaceHolder(this._blobContainerStorageAccountDropdown, constants.NO_STORAGE_ACCOUNT_FOUND);
|
||||
}
|
||||
}
|
||||
this._blobContainerStorageAccountDropdown.loading = false;
|
||||
await this.loadBlobContainerDropdown();
|
||||
}
|
||||
|
||||
private async loadStorageAccounts(subscriptionId: string): Promise<StorageAccount[]> {
|
||||
const storageAccounts = await getAvailableStorageAccounts(this.migrationStateModel.azureAccount, this._subscriptionMap.get(subscriptionId)!);
|
||||
storageAccounts.forEach(s => {
|
||||
this._storageAccountMap.set(s.id, s);
|
||||
});
|
||||
return storageAccounts;
|
||||
}
|
||||
|
||||
private async loadFileShareDropdown(): Promise<void> {
|
||||
this._fileShareFileShareDropdown.loading = true;
|
||||
const storageAccountId = (<azdata.CategoryValue>this._fileShareStorageAccountDropdown.value).name;
|
||||
if (!storageAccountId.length) {
|
||||
this.setEmptyDropdownPlaceHolder(this._fileShareFileShareDropdown, constants.NO_FILESHARES_FOUND);
|
||||
} else {
|
||||
const fileShares = await getFileShares(this.migrationStateModel.azureAccount, this._subscriptionMap.get(this._fileShare.subscriptionId)!, this._storageAccountMap.get(storageAccountId)!);
|
||||
if (fileShares && fileShares.length) {
|
||||
this._fileShareFileShareDropdown.values = fileShares.map(f => <azdata.CategoryValue>{ name: f.id, displayName: f.name });
|
||||
this._fileShare.fileShareId = fileShares[0].id!;
|
||||
} else {
|
||||
this.setEmptyDropdownPlaceHolder(this._fileShareFileShareDropdown, constants.NO_FILESHARES_FOUND);
|
||||
}
|
||||
try {
|
||||
this._fileShareFileShareDropdown.values = await this.migrationStateModel.getFileShareValues(this.migrationStateModel.databaseBackup.subscription, this.migrationStateModel.databaseBackup.storageAccount);
|
||||
this.migrationStateModel.databaseBackup.fileShare = this.migrationStateModel.getFileShare(0);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
this._fileShareFileShareDropdown.loading = false;
|
||||
}
|
||||
this._fileShareFileShareDropdown.loading = false;
|
||||
}
|
||||
|
||||
private async loadBlobContainerDropdown(): Promise<void> {
|
||||
this._blobContainerBlobDropdown.loading = true;
|
||||
const storageAccountId = (<azdata.CategoryValue>this._blobContainerStorageAccountDropdown.value).name;
|
||||
if (!storageAccountId.length) {
|
||||
this.setEmptyDropdownPlaceHolder(this._blobContainerBlobDropdown, constants.NO_BLOBCONTAINERS_FOUND);
|
||||
} else {
|
||||
const blobContainers = await getBlobContainers(this.migrationStateModel.azureAccount, this._subscriptionMap.get(this._blob.subscriptionId)!, this._storageAccountMap.get(storageAccountId)!);
|
||||
if (blobContainers && blobContainers.length) {
|
||||
this._blobContainerBlobDropdown.values = blobContainers.map(f => <azdata.CategoryValue>{ name: f.id, displayName: f.name });
|
||||
this._blob.containerId = blobContainers[0].id!;
|
||||
} else {
|
||||
this.setEmptyDropdownPlaceHolder(this._blobContainerBlobDropdown, constants.NO_BLOBCONTAINERS_FOUND);
|
||||
}
|
||||
try {
|
||||
this._blobContainerBlobDropdown.values = await this.migrationStateModel.getBlobContainerValues(this.migrationStateModel.databaseBackup.subscription, this.migrationStateModel.databaseBackup.storageAccount);
|
||||
this.migrationStateModel.databaseBackup.blobContainer = this.migrationStateModel.getBlobContainer(0);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
this._blobContainerBlobDropdown.loading = false;
|
||||
}
|
||||
this._blobContainerBlobDropdown.loading = false;
|
||||
}
|
||||
|
||||
private setEmptyDropdownPlaceHolder(dropDown: azdata.DropDownComponent, placeholder: string): void {
|
||||
dropDown.values = [{
|
||||
displayName: placeholder,
|
||||
name: ''
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,23 +4,19 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
|
||||
import { CreateMigrationControllerDialog } from './createMigrationControllerDialog';
|
||||
import * as constants from '../models/strings';
|
||||
import * as os from 'os';
|
||||
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
||||
|
||||
export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
|
||||
private migrationControllerDropdown!: azdata.DropDownComponent;
|
||||
private defaultSetupRadioButton!: azdata.RadioButtonComponent;
|
||||
private customSetupRadioButton!: azdata.RadioButtonComponent;
|
||||
private startSetupButton!: azdata.ButtonComponent;
|
||||
private cancelSetupButton!: azdata.ButtonComponent;
|
||||
private _connectionStatus!: azdata.TextComponent;
|
||||
private createMigrationContainer!: azdata.FlexContainer;
|
||||
private _connectionStatus!: azdata.InfoBoxComponent;
|
||||
private _view!: azdata.ModelView;
|
||||
private _form!: azdata.FormBuilder;
|
||||
|
||||
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
|
||||
super(wizard, azdata.window.createWizardPage(constants.IR_PAGE_TITLE), migrationStateModel);
|
||||
@@ -29,79 +25,19 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
protected async registerContent(view: azdata.ModelView): Promise<void> {
|
||||
this._view = view;
|
||||
|
||||
const createNewController = view.modelBuilder.button().withProps({
|
||||
label: constants.NEW,
|
||||
width: '100px',
|
||||
secondary: true
|
||||
const createNewController = view.modelBuilder.hyperlink().withProps({
|
||||
label: constants.CREATE_NEW,
|
||||
url: ''
|
||||
}).component();
|
||||
|
||||
createNewController.onDidClick((e) => {
|
||||
this.createMigrationContainer.display = 'inline';
|
||||
const dialog = new CreateMigrationControllerDialog(this.migrationStateModel, this);
|
||||
dialog.initialize();
|
||||
});
|
||||
|
||||
const setupButtonGroup = 'setupOptions';
|
||||
this._connectionStatus = view.modelBuilder.infoBox().component();
|
||||
|
||||
this.defaultSetupRadioButton = view.modelBuilder.radioButton().withProps({
|
||||
label: constants.DEFAULT_SETUP_BUTTON,
|
||||
name: setupButtonGroup
|
||||
}).component();
|
||||
this.defaultSetupRadioButton.checked = true;
|
||||
|
||||
this.customSetupRadioButton = view.modelBuilder.radioButton().withProps({
|
||||
label: constants.CUSTOM_SETUP_BUTTON,
|
||||
name: setupButtonGroup
|
||||
}).component();
|
||||
|
||||
this.startSetupButton = view.modelBuilder.button().withProps({
|
||||
label: constants.CREATE,
|
||||
width: '100px',
|
||||
secondary: true
|
||||
}).component();
|
||||
|
||||
this.startSetupButton.onDidClick((e) => {
|
||||
if (this.defaultSetupRadioButton.checked) {
|
||||
vscode.window.showInformationMessage(constants.FEATURE_NOT_AVAILABLE);
|
||||
} else {
|
||||
this.createMigrationContainer.display = 'none';
|
||||
const dialog = new CreateMigrationControllerDialog(this.migrationStateModel, this);
|
||||
dialog.initialize();
|
||||
}
|
||||
});
|
||||
|
||||
this.cancelSetupButton = view.modelBuilder.button().withProps({
|
||||
label: constants.CANCEL,
|
||||
width: '100px',
|
||||
secondary: true
|
||||
}).component();
|
||||
|
||||
this.cancelSetupButton.onDidClick((e) => {
|
||||
this.createMigrationContainer.display = 'none';
|
||||
});
|
||||
|
||||
const setupButtonsContainer = view.modelBuilder.flexContainer().withItems([
|
||||
this.startSetupButton,
|
||||
this.cancelSetupButton
|
||||
],
|
||||
{ CSSStyles: { 'margin': '10px', } }
|
||||
).withLayout({
|
||||
flexFlow: 'row'
|
||||
}).component();
|
||||
|
||||
this.createMigrationContainer = view.modelBuilder.flexContainer().withItems(
|
||||
[
|
||||
this.defaultSetupRadioButton,
|
||||
this.customSetupRadioButton,
|
||||
setupButtonsContainer
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
|
||||
this._connectionStatus = view.modelBuilder.text().component();
|
||||
|
||||
this.createMigrationContainer.display = 'none';
|
||||
|
||||
const form = view.modelBuilder.formContainer()
|
||||
this._form = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[
|
||||
{
|
||||
@@ -110,16 +46,13 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
{
|
||||
component: createNewController
|
||||
},
|
||||
{
|
||||
component: this.createMigrationContainer
|
||||
},
|
||||
{
|
||||
component: this._connectionStatus
|
||||
}
|
||||
|
||||
]
|
||||
);
|
||||
await view.initializeModel(form.component());
|
||||
await view.initializeModel(this._form.component());
|
||||
}
|
||||
|
||||
public async onPageEnter(): Promise<void> {
|
||||
@@ -148,6 +81,9 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
}
|
||||
|
||||
public async onPageLeave(): Promise<void> {
|
||||
this.wizard.registerNavigationValidator((pageChangeInfo) => {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
|
||||
@@ -164,16 +100,22 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
]
|
||||
}).component();
|
||||
|
||||
const noteText = this._view.modelBuilder.text().withProps({
|
||||
value: constants.IR_PAGE_NOTE
|
||||
}).component();
|
||||
|
||||
const migrationControllerDropdownLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SELECT_A_MIGRATION_CONTROLLER
|
||||
}).component();
|
||||
|
||||
this.migrationControllerDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
required: true,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH
|
||||
}).component();
|
||||
|
||||
const flexContainer = this._view.modelBuilder.flexContainer().withItems([
|
||||
descriptionText,
|
||||
noteText,
|
||||
migrationControllerDropdownLabel,
|
||||
this.migrationControllerDropdown
|
||||
]).withLayout({
|
||||
@@ -183,16 +125,34 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
}
|
||||
|
||||
public async populateMigrationController(controllerStatus?: string): Promise<void> {
|
||||
this.migrationControllerDropdown.loading = true;
|
||||
let migrationContollerValues: azdata.CategoryValue[] = [];
|
||||
|
||||
// TODO: Replace with this code when APIs are deployed.
|
||||
// try{
|
||||
// this.migrationControllerDropdown.values = await this.migrationStateModel.getMigrationControllerValues(this.migrationStateModel._targetSubscription, this.migrationStateModel._targetManagedInstance);
|
||||
// this.migrationStateModel.migrationController = this.migrationStateModel.getMigrationController(0);
|
||||
// } catch (e) {
|
||||
|
||||
// } finally {
|
||||
// this.migrationControllerDropdown.loading = false;
|
||||
// }
|
||||
|
||||
if (this.migrationStateModel.migrationController) {
|
||||
|
||||
this._connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.CONTROLLER_READY(this.migrationStateModel.migrationController!.name, this.migrationStateModel._nodeNames.join(', ')),
|
||||
style: 'success'
|
||||
});
|
||||
this._form.addFormItem({
|
||||
component: this._connectionStatus
|
||||
});
|
||||
migrationContollerValues = [
|
||||
{
|
||||
displayName: this.migrationStateModel.migrationController.name,
|
||||
name: this.migrationStateModel.migrationController.name
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
|
||||
this._connectionStatus.value = constants.CONTRLLER_READY(this.migrationStateModel.migrationController!.name, os.hostname());
|
||||
}
|
||||
else {
|
||||
migrationContollerValues = [
|
||||
@@ -201,7 +161,9 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
this._connectionStatus.value = '';
|
||||
this._form.removeFormItem({
|
||||
component: this._connectionStatus
|
||||
});
|
||||
}
|
||||
this.migrationControllerDropdown.values = migrationContollerValues;
|
||||
this.migrationControllerDropdown.loading = false;
|
||||
|
||||
150
extensions/sql-migration/src/wizard/summaryPage.ts
Normal file
150
extensions/sql-migration/src/wizard/summaryPage.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../models/strings';
|
||||
|
||||
export class SummaryPage extends MigrationWizardPage {
|
||||
private _view!: azdata.ModelView;
|
||||
private _flexContainer!: azdata.FlexContainer;
|
||||
|
||||
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
|
||||
super(wizard, azdata.window.createWizardPage(constants.SUMMARY_PAGE_TITLE), migrationStateModel);
|
||||
}
|
||||
|
||||
protected async registerContent(view: azdata.ModelView): Promise<void> {
|
||||
this._view = view;
|
||||
this._flexContainer = view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
const form = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[
|
||||
{
|
||||
component: this._flexContainer
|
||||
}
|
||||
]
|
||||
);
|
||||
await view.initializeModel(form.component());
|
||||
}
|
||||
|
||||
public async onPageEnter(): Promise<void> {
|
||||
this._flexContainer.addItems(
|
||||
[
|
||||
this.createHeadingTextComponent(constants.AZURE_ACCOUNT_LINKED),
|
||||
this.createHeadingTextComponent(this.migrationStateModel.azureAccount.displayInfo.displayName),
|
||||
|
||||
|
||||
this.createHeadingTextComponent(constants.MIGRATION_TARGET),
|
||||
this.createInformationRow(constants.TYPE, constants.SUMMARY_MI_TYPE),
|
||||
this.createInformationRow(constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name),
|
||||
this.createInformationRow(constants.SUMMARY_MI_TYPE, this.migrationStateModel._targetManagedInstance.name),
|
||||
this.createInformationRow(constants.SUMMARY_DATABASE_COUNT_LABEL, '1'),
|
||||
|
||||
this.createHeadingTextComponent(constants.DATABASE_BACKUP_PAGE_TITLE),
|
||||
this.createNetworkContainerRows(),
|
||||
|
||||
this.createHeadingTextComponent(constants.IR_PAGE_TITLE),
|
||||
this.createInformationRow(constants.IR_PAGE_TITLE, this.migrationStateModel.migrationController?.name!),
|
||||
this.createInformationRow(constants.SUMMARY_IR_NODE, this.migrationStateModel._nodeNames.join(', ')),
|
||||
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public async onPageLeave(): Promise<void> {
|
||||
this._flexContainer.clearItems();
|
||||
this.wizard.registerNavigationValidator(async (pageChangeInfo) => {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
|
||||
}
|
||||
|
||||
private createInformationRow(label: string, value: string): azdata.FlexContainer {
|
||||
return this._view.modelBuilder.flexContainer()
|
||||
.withLayout(
|
||||
{
|
||||
flexFlow: 'row',
|
||||
alignItems: 'center',
|
||||
})
|
||||
.withItems(
|
||||
[
|
||||
this.creaetLabelTextComponent(label),
|
||||
this.createTextCompononent(value)
|
||||
],
|
||||
{
|
||||
CSSStyles: { 'margin-right': '5px' }
|
||||
})
|
||||
.component();
|
||||
}
|
||||
|
||||
private createHeadingTextComponent(value: string): azdata.TextComponent {
|
||||
const component = this.createTextCompononent(value);
|
||||
component.updateCssStyles({
|
||||
'font-size': '13px',
|
||||
'font-weight': 'bold'
|
||||
});
|
||||
return component;
|
||||
}
|
||||
|
||||
|
||||
private creaetLabelTextComponent(value: string): azdata.TextComponent {
|
||||
const component = this.createTextCompononent(value);
|
||||
component.updateCssStyles({
|
||||
'color': '#595959',
|
||||
'width': '250px'
|
||||
});
|
||||
return component;
|
||||
}
|
||||
|
||||
private createTextCompononent(value: string): azdata.TextComponent {
|
||||
return this._view.modelBuilder.text().withProps({
|
||||
value: value
|
||||
}).component();
|
||||
}
|
||||
|
||||
private createNetworkContainerRows(): azdata.FlexContainer {
|
||||
const flexContainer = this._view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
switch (this.migrationStateModel.databaseBackup.networkContainerType) {
|
||||
case NetworkContainerType.NETWORK_SHARE:
|
||||
flexContainer.addItems(
|
||||
[
|
||||
this.createInformationRow(constants.TYPE, constants.NETWORK_SHARE),
|
||||
this.createInformationRow(constants.PATH, this.migrationStateModel.databaseBackup.networkShareLocation),
|
||||
this.createInformationRow(constants.USER_ACCOUNT, this.migrationStateModel.databaseBackup.windowsUser),
|
||||
this.createInformationRow(constants.SUMMARY_AZURE_STORAGE_SUBSCRIPTION, this.migrationStateModel.databaseBackup.subscription.name),
|
||||
this.createInformationRow(constants.SUMMARY_AZURE_STORAGE, this.migrationStateModel.databaseBackup.storageAccount.name),
|
||||
]
|
||||
);
|
||||
break;
|
||||
case NetworkContainerType.FILE_SHARE:
|
||||
flexContainer.addItems(
|
||||
[
|
||||
this.createInformationRow(constants.TYPE, constants.FILE_SHARE),
|
||||
this.createInformationRow(constants.SUMMARY_AZURE_STORAGE_SUBSCRIPTION, this.migrationStateModel.databaseBackup.subscription.name),
|
||||
this.createInformationRow(constants.SUMMARY_AZURE_STORAGE, this.migrationStateModel.databaseBackup.storageAccount.name),
|
||||
this.createInformationRow(constants.FILE_SHARE, this.migrationStateModel.databaseBackup.fileShare.name),
|
||||
]
|
||||
);
|
||||
break;
|
||||
case NetworkContainerType.BLOB_CONTAINER:
|
||||
flexContainer.addItems(
|
||||
[
|
||||
this.createInformationRow(constants.TYPE, constants.BLOB_CONTAINER),
|
||||
this.createInformationRow(constants.SUMMARY_AZURE_STORAGE_SUBSCRIPTION, this.migrationStateModel.databaseBackup.blobContainer.subscription.name),
|
||||
this.createInformationRow(constants.SUMMARY_AZURE_STORAGE, this.migrationStateModel.databaseBackup.storageAccount.name),
|
||||
this.createInformationRow(constants.BLOB_CONTAINER, this.migrationStateModel.databaseBackup.blobContainer.name),
|
||||
]
|
||||
);
|
||||
}
|
||||
return flexContainer;
|
||||
}
|
||||
}
|
||||
@@ -4,19 +4,15 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { azureResource } from 'azureResource';
|
||||
import { getAvailableManagedInstanceProducts, getSubscriptions, SqlManagedInstance, Subscription } from '../api/azure';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../models/strings';
|
||||
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
||||
|
||||
export class TempTargetSelectionPage extends MigrationWizardPage {
|
||||
|
||||
private _managedInstanceSubscriptionDropdown!: azdata.DropDownComponent;
|
||||
private _managedInstanceDropdown!: azdata.DropDownComponent;
|
||||
private _subscriptionDropdownValues: azdata.CategoryValue[] = [];
|
||||
private _subscriptionMap: Map<string, Subscription> = new Map();
|
||||
|
||||
|
||||
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
|
||||
super(wizard, azdata.window.createWizardPage(constants.TARGET_SELECTION_PAGE_TITLE), migrationStateModel);
|
||||
@@ -24,17 +20,37 @@ export class TempTargetSelectionPage extends MigrationWizardPage {
|
||||
|
||||
protected async registerContent(view: azdata.ModelView): Promise<void> {
|
||||
|
||||
const managedInstanceSubscriptionDropdownLabel = view.modelBuilder.text().withProps({
|
||||
value: constants.SUBSCRIPTION
|
||||
}).component();
|
||||
this._managedInstanceSubscriptionDropdown = view.modelBuilder.dropDown().component();
|
||||
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) => {
|
||||
this.populateManagedInstanceDropdown();
|
||||
if (e.selected) {
|
||||
this.migrationStateModel._targetSubscription = this.migrationStateModel.getSubscription(e.index);
|
||||
this.migrationStateModel._targetManagedInstances = undefined!;
|
||||
this.populateManagedInstanceDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
const managedInstanceDropdownLabel = view.modelBuilder.text().withProps({
|
||||
value: constants.MANAGED_INSTANCE
|
||||
}).component();
|
||||
this._managedInstanceDropdown = view.modelBuilder.dropDown().component();
|
||||
|
||||
this._managedInstanceDropdown = view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH
|
||||
}).component();
|
||||
this._managedInstanceDropdown.onValueChanged((e) => {
|
||||
if (e.selected) {
|
||||
this.migrationStateModel.migrationControllers = undefined!;
|
||||
this.migrationStateModel._targetManagedInstance = this.migrationStateModel.getManagedInstance(e.index);
|
||||
}
|
||||
});
|
||||
|
||||
const targetContainer = view.modelBuilder.flexContainer().withItems(
|
||||
[
|
||||
@@ -61,6 +77,8 @@ export class TempTargetSelectionPage extends MigrationWizardPage {
|
||||
this.populateSubscriptionDropdown();
|
||||
}
|
||||
public async onPageLeave(): Promise<void> {
|
||||
console.log(this.migrationStateModel._targetSubscription);
|
||||
console.log(this.migrationStateModel._targetManagedInstance);
|
||||
}
|
||||
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
|
||||
}
|
||||
@@ -68,71 +86,26 @@ export class TempTargetSelectionPage extends MigrationWizardPage {
|
||||
private async populateSubscriptionDropdown(): Promise<void> {
|
||||
this._managedInstanceSubscriptionDropdown.loading = true;
|
||||
this._managedInstanceDropdown.loading = true;
|
||||
let subscriptions: azureResource.AzureResourceSubscription[] = [];
|
||||
|
||||
try {
|
||||
subscriptions = await getSubscriptions(this.migrationStateModel.azureAccount);
|
||||
subscriptions.forEach((subscription) => {
|
||||
this._subscriptionMap.set(subscription.id, subscription);
|
||||
this._subscriptionDropdownValues.push({
|
||||
name: subscription.id,
|
||||
displayName: subscription.name + ' - ' + subscription.id,
|
||||
});
|
||||
});
|
||||
|
||||
if (!this._subscriptionDropdownValues || this._subscriptionDropdownValues.length === 0) {
|
||||
this._subscriptionDropdownValues = [
|
||||
{
|
||||
displayName: constants.NO_SUBSCRIPTIONS_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
this._managedInstanceSubscriptionDropdown.values = this._subscriptionDropdownValues;
|
||||
} catch (error) {
|
||||
this.setEmptyDropdownPlaceHolder(this._managedInstanceSubscriptionDropdown, constants.NO_SUBSCRIPTIONS_FOUND);
|
||||
this._managedInstanceSubscriptionDropdown.values = await this.migrationStateModel.getSubscriptionsDropdownValues();
|
||||
this.migrationStateModel._targetSubscription = this.migrationStateModel.getSubscription(0);
|
||||
} catch (e) {
|
||||
this.migrationStateModel._targetManagedInstances = undefined!;
|
||||
} finally {
|
||||
this.populateManagedInstanceDropdown();
|
||||
this._managedInstanceSubscriptionDropdown.loading = false;
|
||||
this._managedInstanceDropdown.loading = false;
|
||||
}
|
||||
this.populateManagedInstanceDropdown();
|
||||
this._managedInstanceSubscriptionDropdown.loading = false;
|
||||
}
|
||||
|
||||
private async populateManagedInstanceDropdown(): Promise<void> {
|
||||
this._managedInstanceDropdown.loading = true;
|
||||
let mis: SqlManagedInstance[] = [];
|
||||
let miValues: azdata.CategoryValue[] = [];
|
||||
try {
|
||||
const subscriptionId = (<azdata.CategoryValue>this._managedInstanceSubscriptionDropdown.value).name;
|
||||
|
||||
mis = await getAvailableManagedInstanceProducts(this.migrationStateModel.azureAccount, this._subscriptionMap.get(subscriptionId)!);
|
||||
mis.forEach((mi) => {
|
||||
miValues.push({
|
||||
name: mi.name,
|
||||
displayName: mi.name
|
||||
});
|
||||
});
|
||||
|
||||
if (!miValues || miValues.length === 0) {
|
||||
miValues = [
|
||||
{
|
||||
displayName: constants.NO_MANAGED_INSTANCE_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
this._managedInstanceDropdown.values = miValues;
|
||||
} catch (error) {
|
||||
this.setEmptyDropdownPlaceHolder(this._managedInstanceDropdown, constants.NO_MANAGED_INSTANCE_FOUND);
|
||||
this._managedInstanceDropdown.values = await this.migrationStateModel.getManagedInstanceValues(this.migrationStateModel._targetSubscription);
|
||||
this.migrationStateModel._targetManagedInstance = this.migrationStateModel.getManagedInstance(0);
|
||||
} finally {
|
||||
this._managedInstanceDropdown.loading = false;
|
||||
}
|
||||
|
||||
this._managedInstanceDropdown.loading = false;
|
||||
}
|
||||
|
||||
private setEmptyDropdownPlaceHolder(dropDown: azdata.DropDownComponent, placeholder: string): void {
|
||||
dropDown.values = [{
|
||||
displayName: placeholder,
|
||||
name: ''
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@ import { DatabaseBackupPage } from './databaseBackupPage';
|
||||
import { AccountsSelectionPage } from './accountsSelectionPage';
|
||||
import { IntergrationRuntimePage } from './integrationRuntimePage';
|
||||
import { TempTargetSelectionPage } from './tempTargetSelectionPage';
|
||||
import { SummaryPage } from './summaryPage';
|
||||
|
||||
export const WIZARD_INPUT_COMPONENT_WIDTH = '400px';
|
||||
export class WizardController {
|
||||
constructor(private readonly extensionContext: vscode.ExtensionContext) {
|
||||
|
||||
@@ -34,7 +36,6 @@ export class WizardController {
|
||||
const wizard = azdata.window.createWizard(WIZARD_TITLE, 'wide');
|
||||
wizard.generateScriptButton.enabled = false;
|
||||
wizard.generateScriptButton.hidden = true;
|
||||
// Disabling unused pages
|
||||
const sourceConfigurationPage = new SourceConfigurationPage(wizard, stateModel);
|
||||
const skuRecommendationPage = new SKURecommendationPage(wizard, stateModel);
|
||||
// const subscriptionSelectionPage = new SubscriptionSelectionPage(wizard, stateModel);
|
||||
@@ -42,6 +43,7 @@ export class WizardController {
|
||||
const tempTargetSelectionPage = new TempTargetSelectionPage(wizard, stateModel);
|
||||
const databaseBackupPage = new DatabaseBackupPage(wizard, stateModel);
|
||||
const integrationRuntimePage = new IntergrationRuntimePage(wizard, stateModel);
|
||||
const summaryPage = new SummaryPage(wizard, stateModel);
|
||||
|
||||
const pages: MigrationWizardPage[] = [
|
||||
// subscriptionSelectionPage,
|
||||
@@ -50,7 +52,8 @@ export class WizardController {
|
||||
sourceConfigurationPage,
|
||||
skuRecommendationPage,
|
||||
databaseBackupPage,
|
||||
integrationRuntimePage
|
||||
integrationRuntimePage,
|
||||
summaryPage
|
||||
];
|
||||
|
||||
wizard.pages = pages.map(p => p.getwizardPage());
|
||||
@@ -79,5 +82,9 @@ export class WizardController {
|
||||
|
||||
await Promise.all(wizardSetupPromises);
|
||||
await pages[0].onPageEnter();
|
||||
|
||||
wizard.doneButton.onClick(async (e) => {
|
||||
await stateModel.startMigration();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user