mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-22 01:25:38 -05:00
Add SQL DB offline migration wizard experience (#20403)
* sql db wizard with target selection * add database table selection * add sqldb to service and IR page * Code complete * navigation bug fixes * fix target db selection * improve sqldb error and status reporting * fix error count bug * remove table status inference * address review feedback * update resource strings and content * fix migraton status string, use localized value * fix ux navigation issues * fix back/fwd w/o changes from changing data
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -219,9 +219,9 @@ export class DatabaseSelectorPage extends MigrationWizardPage {
|
||||
]
|
||||
}).component();
|
||||
|
||||
this._disposables.push(this._databaseSelectorTable.onRowSelected(async (e) => {
|
||||
await this.updateValuesOnSelection();
|
||||
}));
|
||||
this._disposables.push(
|
||||
this._databaseSelectorTable.onRowSelected(
|
||||
async (e) => await this.updateValuesOnSelection()));
|
||||
|
||||
// load unfiltered table list and pre-select list of databases saved in state
|
||||
await this._filterTableList('', this.migrationStateModel._databasesForAssessment);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationStateModel, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
|
||||
import { MigrationStateModel, MigrationTargetType, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
|
||||
import { CreateSqlMigrationServiceDialog } from '../dialog/createSqlMigrationService/createSqlMigrationServiceDialog';
|
||||
import * as constants from '../constants/strings';
|
||||
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
||||
@@ -17,20 +17,17 @@ import * as utils from '../api/utils';
|
||||
import * as styles from '../constants/styles';
|
||||
|
||||
export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
|
||||
private _view!: azdata.ModelView;
|
||||
private _statusLoadingComponent!: azdata.LoadingComponent;
|
||||
private _subscription!: azdata.TextComponent;
|
||||
private _location!: azdata.TextComponent;
|
||||
private _resourceGroupDropdown!: azdata.DropDownComponent;
|
||||
private _dmsDropdown!: azdata.DropDownComponent;
|
||||
|
||||
private _dmsInfoContainer!: azdata.FlexContainer;
|
||||
private _dmsStatusInfoBox!: azdata.InfoBoxComponent;
|
||||
private _authKeyTable!: azdata.DeclarativeTableComponent;
|
||||
private _refreshButton!: azdata.ButtonComponent;
|
||||
private _connectionStatusLoader!: azdata.LoadingComponent;
|
||||
|
||||
private _copy1!: azdata.ButtonComponent;
|
||||
private _copy2!: azdata.ButtonComponent;
|
||||
private _refresh1!: azdata.ButtonComponent;
|
||||
@@ -55,31 +52,39 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
const form = view.modelBuilder.formContainer()
|
||||
.withFormItems([
|
||||
{ component: this.migrationServiceDropdownContainer() },
|
||||
{ component: this._dmsInfoContainer }
|
||||
])
|
||||
{ component: this._dmsInfoContainer }])
|
||||
.withProps({ CSSStyles: { 'padding-top': '0' } })
|
||||
.component();
|
||||
|
||||
this._disposables.push(this._view.onClosed(e => {
|
||||
this._disposables.forEach(
|
||||
d => { try { d.dispose(); } catch { } });
|
||||
}));
|
||||
this._disposables.push(
|
||||
this._view.onClosed(e =>
|
||||
this._disposables.forEach(
|
||||
d => { try { d.dispose(); } catch { } })));
|
||||
|
||||
await view.initializeModel(form);
|
||||
}
|
||||
|
||||
public async onPageEnter(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
|
||||
if (pageChangeInfo.newPage < pageChangeInfo.lastPage) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._subscription.value = this.migrationStateModel._targetSubscription.name;
|
||||
this._location.value = await getLocationDisplayName(this.migrationStateModel._targetServerInstance.location);
|
||||
this._dmsInfoContainer.display = (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE && this.migrationStateModel._sqlMigrationService) ? 'inline' : 'none';
|
||||
this._location.value = await getLocationDisplayName(
|
||||
this.migrationStateModel._targetServerInstance.location);
|
||||
|
||||
await utils.updateControlDisplay(
|
||||
this._dmsInfoContainer,
|
||||
this.migrationStateModel._targetType === MigrationTargetType.SQLDB ||
|
||||
this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE);
|
||||
|
||||
await this.loadResourceGroupDropdown();
|
||||
this.wizard.registerNavigationValidator((pageChangeInfo) => {
|
||||
this.wizard.message = { text: '' };
|
||||
if (pageChangeInfo.newPage < pageChangeInfo.lastPage) {
|
||||
this.wizard.message = {
|
||||
text: ''
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
const state = this.migrationStateModel._sqlMigrationService?.properties?.integrationRuntimeState;
|
||||
if (!this.migrationStateModel._sqlMigrationService) {
|
||||
this.wizard.message = {
|
||||
@@ -88,327 +93,325 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
};
|
||||
return false;
|
||||
}
|
||||
if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE && state !== 'Online') {
|
||||
if ((this.migrationStateModel._targetType === MigrationTargetType.SQLDB ||
|
||||
this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE)
|
||||
&& state !== 'Online') {
|
||||
|
||||
this.wizard.message = {
|
||||
level: azdata.window.MessageLevel.Error,
|
||||
text: constants.SERVICE_OFFLINE_ERROR
|
||||
};
|
||||
return false;
|
||||
} else {
|
||||
this.wizard.message = {
|
||||
text: ''
|
||||
};
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public async onPageLeave(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
|
||||
this.wizard.registerNavigationValidator((pageChangeInfo) => {
|
||||
return true;
|
||||
});
|
||||
this.wizard.registerNavigationValidator((pageChangeInfo) => true);
|
||||
}
|
||||
|
||||
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
|
||||
}
|
||||
|
||||
private migrationServiceDropdownContainer(): azdata.FlexContainer {
|
||||
const descriptionText = this._view.modelBuilder.text().withProps({
|
||||
value: constants.IR_PAGE_DESCRIPTION,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
CSSStyles: {
|
||||
...styles.BODY_CSS,
|
||||
'margin-bottom': '16px'
|
||||
}
|
||||
}).component();
|
||||
const descriptionText = this._view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.IR_PAGE_DESCRIPTION,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
CSSStyles: { ...styles.BODY_CSS, 'margin-bottom': '16px' }
|
||||
}).component();
|
||||
|
||||
const subscriptionLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SUBSCRIPTION,
|
||||
CSSStyles: {
|
||||
...styles.LABEL_CSS
|
||||
}
|
||||
}).component();
|
||||
this._subscription = this._view.modelBuilder.text().withProps({
|
||||
enabled: false,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
CSSStyles: {
|
||||
'margin': '0'
|
||||
}
|
||||
}).component();
|
||||
const subscriptionLabel = this._view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.SUBSCRIPTION,
|
||||
CSSStyles: { ...styles.LABEL_CSS }
|
||||
}).component();
|
||||
this._subscription = this._view.modelBuilder.text()
|
||||
.withProps({
|
||||
enabled: false,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
CSSStyles: { 'margin': '0' }
|
||||
}).component();
|
||||
|
||||
const locationLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.LOCATION,
|
||||
CSSStyles: {
|
||||
...styles.LABEL_CSS,
|
||||
'margin-top': '1em'
|
||||
}
|
||||
}).component();
|
||||
this._location = this._view.modelBuilder.text().withProps({
|
||||
enabled: false,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
CSSStyles: {
|
||||
'margin': '0'
|
||||
}
|
||||
}).component();
|
||||
const locationLabel = this._view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.LOCATION,
|
||||
CSSStyles: { ...styles.LABEL_CSS, 'margin-top': '1em' }
|
||||
}).component();
|
||||
this._location = this._view.modelBuilder.text()
|
||||
.withProps({
|
||||
enabled: false,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
CSSStyles: { 'margin': '0' }
|
||||
}).component();
|
||||
|
||||
const resourceGroupLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.RESOURCE_GROUP,
|
||||
requiredIndicator: true,
|
||||
CSSStyles: {
|
||||
...styles.LABEL_CSS
|
||||
}
|
||||
}).component();
|
||||
this._resourceGroupDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
ariaLabel: constants.RESOURCE_GROUP,
|
||||
placeholder: constants.SELECT_RESOURCE_GROUP,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
editable: true,
|
||||
required: true,
|
||||
fireOnTextChange: true,
|
||||
CSSStyles: {
|
||||
'margin-top': '-1em'
|
||||
}
|
||||
}).component();
|
||||
this._disposables.push(this._resourceGroupDropdown.onValueChanged(async (value) => {
|
||||
if (value && value !== 'undefined' && value !== constants.RESOURCE_GROUP_NOT_FOUND) {
|
||||
const selectedResourceGroup = this.migrationStateModel._resourceGroups.find(rg => rg.name === value);
|
||||
this.migrationStateModel._sqlMigrationServiceResourceGroup = (selectedResourceGroup)
|
||||
? selectedResourceGroup
|
||||
: undefined!;
|
||||
await this.populateDms();
|
||||
}
|
||||
}));
|
||||
const resourceGroupLabel = this._view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.RESOURCE_GROUP,
|
||||
requiredIndicator: true,
|
||||
CSSStyles: { ...styles.LABEL_CSS }
|
||||
}).component();
|
||||
this._resourceGroupDropdown = this._view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
ariaLabel: constants.RESOURCE_GROUP,
|
||||
placeholder: constants.SELECT_RESOURCE_GROUP,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
editable: true,
|
||||
required: true,
|
||||
fireOnTextChange: true,
|
||||
CSSStyles: { 'margin-top': '-1em' }
|
||||
}).component();
|
||||
this._disposables.push(
|
||||
this._resourceGroupDropdown.onValueChanged(
|
||||
async (value) => {
|
||||
if (value && value !== 'undefined' && value !== constants.RESOURCE_GROUP_NOT_FOUND) {
|
||||
const selectedResourceGroup = this.migrationStateModel._resourceGroups.find(rg => rg.name === value);
|
||||
this.migrationStateModel._sqlMigrationServiceResourceGroup = (selectedResourceGroup)
|
||||
? selectedResourceGroup
|
||||
: undefined!;
|
||||
this.populateDms();
|
||||
}
|
||||
}));
|
||||
|
||||
const migrationServiceDropdownLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.IR_PAGE_TITLE,
|
||||
requiredIndicator: true,
|
||||
CSSStyles: {
|
||||
...styles.LABEL_CSS
|
||||
}
|
||||
}).component();
|
||||
this._dmsDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
ariaLabel: constants.IR_PAGE_TITLE,
|
||||
placeholder: constants.SELECT_RESOURCE_GROUP_PROMPT,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
editable: true,
|
||||
required: true,
|
||||
fireOnTextChange: true,
|
||||
CSSStyles: {
|
||||
'margin-top': '-1em'
|
||||
}
|
||||
}).component();
|
||||
this._disposables.push(this._dmsDropdown.onValueChanged(async (value) => {
|
||||
if (value && value !== 'undefined' && value !== constants.SQL_MIGRATION_SERVICE_NOT_FOUND_ERROR) {
|
||||
if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
this._dmsInfoContainer.display = 'inline';
|
||||
}
|
||||
this.wizard.message = {
|
||||
text: ''
|
||||
};
|
||||
const selectedDms = this.migrationStateModel._sqlMigrationServices.find(dms => dms.name === value && dms.properties.resourceGroup.toLowerCase() === this.migrationStateModel._sqlMigrationServiceResourceGroup.name.toLowerCase());
|
||||
if (selectedDms) {
|
||||
this.migrationStateModel._sqlMigrationService = selectedDms;
|
||||
await this.loadMigrationServiceStatus();
|
||||
}
|
||||
} else {
|
||||
this.migrationStateModel._sqlMigrationService = undefined;
|
||||
this._dmsInfoContainer.display = 'none';
|
||||
}
|
||||
}));
|
||||
const migrationServiceDropdownLabel = this._view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.IR_PAGE_TITLE,
|
||||
requiredIndicator: true,
|
||||
CSSStyles: { ...styles.LABEL_CSS }
|
||||
}).component();
|
||||
this._dmsDropdown = this._view.modelBuilder.dropDown()
|
||||
.withProps({
|
||||
ariaLabel: constants.IR_PAGE_TITLE,
|
||||
placeholder: constants.SELECT_RESOURCE_GROUP_PROMPT,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
editable: true,
|
||||
required: true,
|
||||
fireOnTextChange: true,
|
||||
CSSStyles: { 'margin-top': '-1em' }
|
||||
}).component();
|
||||
this._disposables.push(
|
||||
this._dmsDropdown.onValueChanged(
|
||||
async (value) => {
|
||||
if (value && value !== 'undefined' && value !== constants.SQL_MIGRATION_SERVICE_NOT_FOUND_ERROR) {
|
||||
this.wizard.message = { text: '' };
|
||||
|
||||
const createNewMigrationService = this._view.modelBuilder.hyperlink().withProps({
|
||||
label: constants.CREATE_NEW,
|
||||
ariaLabel: constants.CREATE_NEW_MIGRATION_SERVICE,
|
||||
url: '',
|
||||
CSSStyles: {
|
||||
...styles.BODY_CSS
|
||||
}
|
||||
}).component();
|
||||
await utils.updateControlDisplay(
|
||||
this._dmsInfoContainer,
|
||||
this.migrationStateModel._targetType === MigrationTargetType.SQLDB ||
|
||||
this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE);
|
||||
|
||||
this._disposables.push(createNewMigrationService.onDidClick(async (e) => {
|
||||
const dialog = new CreateSqlMigrationServiceDialog();
|
||||
const createdDmsResult = await dialog.createNewDms(this.migrationStateModel, (<azdata.CategoryValue>this._resourceGroupDropdown.value).displayName);
|
||||
this.migrationStateModel._sqlMigrationServiceResourceGroup = createdDmsResult.resourceGroup;
|
||||
this.migrationStateModel._sqlMigrationService = createdDmsResult.service;
|
||||
await this.loadResourceGroupDropdown();
|
||||
await this.populateDms();
|
||||
}));
|
||||
const selectedDms = this.migrationStateModel._sqlMigrationServices.find(
|
||||
dms => dms.name === value && dms.properties.resourceGroup.toLowerCase() === this.migrationStateModel._sqlMigrationServiceResourceGroup.name.toLowerCase());
|
||||
if (selectedDms) {
|
||||
this.migrationStateModel._sqlMigrationService = selectedDms;
|
||||
await this.loadStatus();
|
||||
}
|
||||
} else {
|
||||
this.migrationStateModel._sqlMigrationService = undefined;
|
||||
await utils.updateControlDisplay(this._dmsInfoContainer, false);
|
||||
}
|
||||
}));
|
||||
|
||||
const flexContainer = this._view.modelBuilder.flexContainer().withItems([
|
||||
descriptionText,
|
||||
subscriptionLabel,
|
||||
this._subscription,
|
||||
locationLabel,
|
||||
this._location,
|
||||
resourceGroupLabel,
|
||||
this._resourceGroupDropdown,
|
||||
migrationServiceDropdownLabel,
|
||||
this._dmsDropdown,
|
||||
createNewMigrationService
|
||||
]).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
return flexContainer;
|
||||
const createNewMigrationService = this._view.modelBuilder.hyperlink()
|
||||
.withProps({
|
||||
label: constants.CREATE_NEW,
|
||||
ariaLabel: constants.CREATE_NEW_MIGRATION_SERVICE,
|
||||
url: '',
|
||||
CSSStyles: { ...styles.BODY_CSS }
|
||||
}).component();
|
||||
|
||||
this._disposables.push(
|
||||
createNewMigrationService.onDidClick(
|
||||
async (e) => {
|
||||
const dialog = new CreateSqlMigrationServiceDialog();
|
||||
const createdDmsResult = await dialog.createNewDms(
|
||||
this.migrationStateModel,
|
||||
(<azdata.CategoryValue>this._resourceGroupDropdown.value).displayName);
|
||||
|
||||
this.migrationStateModel._sqlMigrationServiceResourceGroup = createdDmsResult.resourceGroup;
|
||||
this.migrationStateModel._sqlMigrationService = createdDmsResult.service;
|
||||
await this.loadResourceGroupDropdown();
|
||||
this.populateDms();
|
||||
}));
|
||||
|
||||
return this._view.modelBuilder.flexContainer()
|
||||
.withItems([
|
||||
descriptionText,
|
||||
subscriptionLabel,
|
||||
this._subscription,
|
||||
locationLabel,
|
||||
this._location,
|
||||
resourceGroupLabel,
|
||||
this._resourceGroupDropdown,
|
||||
migrationServiceDropdownLabel,
|
||||
this._dmsDropdown,
|
||||
createNewMigrationService])
|
||||
.withLayout({ flexFlow: 'column' })
|
||||
.component();
|
||||
}
|
||||
|
||||
private createDMSDetailsContainer(): azdata.FlexContainer {
|
||||
const container = this._view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
const container = this._view.modelBuilder.flexContainer()
|
||||
.withLayout({ flexFlow: 'column' })
|
||||
.component();
|
||||
|
||||
const connectionStatusLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SERVICE_CONNECTION_STATUS,
|
||||
CSSStyles: {
|
||||
...styles.LABEL_CSS,
|
||||
'width': '130px'
|
||||
}
|
||||
}).component();
|
||||
const connectionStatusLabel = this._view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.SERVICE_CONNECTION_STATUS,
|
||||
CSSStyles: { ...styles.LABEL_CSS, 'width': '130px' }
|
||||
}).component();
|
||||
|
||||
this._refreshButton = this._view.modelBuilder.button().withProps({
|
||||
iconWidth: '18px',
|
||||
iconHeight: '18px',
|
||||
iconPath: IconPathHelper.refresh,
|
||||
height: '18px',
|
||||
width: '18px',
|
||||
ariaLabel: constants.REFRESH,
|
||||
}).component();
|
||||
this._refreshButton = this._view.modelBuilder.button()
|
||||
.withProps({
|
||||
iconWidth: '18px',
|
||||
iconHeight: '18px',
|
||||
iconPath: IconPathHelper.refresh,
|
||||
height: '18px',
|
||||
width: '18px',
|
||||
ariaLabel: constants.REFRESH,
|
||||
}).component();
|
||||
|
||||
this._disposables.push(this._refreshButton.onDidClick(async (e) => {
|
||||
this._connectionStatusLoader.loading = true;
|
||||
try {
|
||||
await this.loadStatus();
|
||||
} finally {
|
||||
this._connectionStatusLoader.loading = false;
|
||||
}
|
||||
}));
|
||||
this._disposables.push(
|
||||
this._refreshButton.onDidClick(
|
||||
async (e) => this.loadStatus()));
|
||||
|
||||
const connectionLabelContainer = this._view.modelBuilder.flexContainer().component();
|
||||
connectionLabelContainer.addItem(connectionStatusLabel, {
|
||||
flex: '0'
|
||||
});
|
||||
connectionLabelContainer.addItem(this._refreshButton, {
|
||||
flex: '0',
|
||||
CSSStyles: { 'margin-right': '10px' }
|
||||
});
|
||||
const connectionLabelContainer = this._view.modelBuilder.flexContainer()
|
||||
.component();
|
||||
connectionLabelContainer.addItem(
|
||||
connectionStatusLabel,
|
||||
{ flex: '0' });
|
||||
connectionLabelContainer.addItem(
|
||||
this._refreshButton,
|
||||
{ flex: '0', CSSStyles: { 'margin-right': '10px' } });
|
||||
|
||||
const statusContainer = this._view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
const statusContainer = this._view.modelBuilder.flexContainer()
|
||||
.withLayout({ flexFlow: 'column' })
|
||||
.component();
|
||||
|
||||
this._dmsStatusInfoBox = this._view.modelBuilder.infoBox().withProps({
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
style: 'error',
|
||||
text: '',
|
||||
CSSStyles: {
|
||||
...styles.BODY_CSS
|
||||
}
|
||||
}).component();
|
||||
this._dmsStatusInfoBox = this._view.modelBuilder.infoBox()
|
||||
.withProps({
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
style: 'error',
|
||||
text: '',
|
||||
CSSStyles: { ...styles.BODY_CSS }
|
||||
}).component();
|
||||
|
||||
const authenticationKeysLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.AUTHENTICATION_KEYS,
|
||||
CSSStyles: {
|
||||
...styles.LABEL_CSS
|
||||
}
|
||||
}).component();
|
||||
const authenticationKeysLabel = this._view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.AUTHENTICATION_KEYS,
|
||||
CSSStyles: { ...styles.LABEL_CSS }
|
||||
}).component();
|
||||
|
||||
this._copy1 = this._view.modelBuilder.button().withProps({
|
||||
title: constants.COPY_KEY1,
|
||||
iconPath: IconPathHelper.copy,
|
||||
ariaLabel: constants.COPY_KEY1,
|
||||
}).component();
|
||||
this._copy1 = this._view.modelBuilder.button()
|
||||
.withProps({
|
||||
title: constants.COPY_KEY1,
|
||||
iconPath: IconPathHelper.copy,
|
||||
ariaLabel: constants.COPY_KEY1,
|
||||
}).component();
|
||||
|
||||
this._disposables.push(this._copy1.onDidClick(async (e) => {
|
||||
await vscode.env.clipboard.writeText(<string>this._authKeyTable.dataValues![0][1].value);
|
||||
void vscode.window.showInformationMessage(constants.SERVICE_KEY1_COPIED_HELP);
|
||||
}));
|
||||
this._disposables.push(
|
||||
this._copy1.onDidClick(
|
||||
async (e) => {
|
||||
await vscode.env.clipboard.writeText(<string>this._authKeyTable.dataValues![0][1].value);
|
||||
void vscode.window.showInformationMessage(constants.SERVICE_KEY1_COPIED_HELP);
|
||||
}));
|
||||
|
||||
this._copy2 = this._view.modelBuilder.button().withProps({
|
||||
title: constants.COPY_KEY2,
|
||||
iconPath: IconPathHelper.copy,
|
||||
ariaLabel: constants.COPY_KEY2,
|
||||
}).component();
|
||||
this._copy2 = this._view.modelBuilder.button()
|
||||
.withProps({
|
||||
title: constants.COPY_KEY2,
|
||||
iconPath: IconPathHelper.copy,
|
||||
ariaLabel: constants.COPY_KEY2,
|
||||
}).component();
|
||||
|
||||
this._disposables.push(this._copy2.onDidClick(async (e) => {
|
||||
await vscode.env.clipboard.writeText(<string>this._authKeyTable.dataValues![1][1].value);
|
||||
void vscode.window.showInformationMessage(constants.SERVICE_KEY2_COPIED_HELP);
|
||||
}));
|
||||
this._disposables.push(
|
||||
this._copy2.onDidClick(async (e) => {
|
||||
await vscode.env.clipboard.writeText(<string>this._authKeyTable.dataValues![1][1].value);
|
||||
void vscode.window.showInformationMessage(constants.SERVICE_KEY2_COPIED_HELP);
|
||||
}));
|
||||
|
||||
this._refresh1 = this._view.modelBuilder.button().withProps({
|
||||
title: constants.REFRESH_KEY1,
|
||||
iconPath: IconPathHelper.refresh,
|
||||
ariaLabel: constants.REFRESH_KEY1,
|
||||
}).component();
|
||||
this._refresh1 = this._view.modelBuilder.button()
|
||||
.withProps({
|
||||
title: constants.REFRESH_KEY1,
|
||||
iconPath: IconPathHelper.refresh,
|
||||
ariaLabel: constants.REFRESH_KEY1,
|
||||
}).component();
|
||||
|
||||
this._refresh2 = this._view.modelBuilder.button().withProps({
|
||||
title: constants.REFRESH_KEY2,
|
||||
iconPath: IconPathHelper.refresh,
|
||||
ariaLabel: constants.REFRESH_KEY2,
|
||||
}).component();
|
||||
this._refresh2 = this._view.modelBuilder.button()
|
||||
.withProps({
|
||||
title: constants.REFRESH_KEY2,
|
||||
iconPath: IconPathHelper.refresh,
|
||||
ariaLabel: constants.REFRESH_KEY2,
|
||||
}).component();
|
||||
|
||||
this._authKeyTable = createAuthenticationKeyTable(this._view);
|
||||
|
||||
statusContainer.addItems([
|
||||
this._dmsStatusInfoBox,
|
||||
authenticationKeysLabel,
|
||||
this._authKeyTable
|
||||
]);
|
||||
this._authKeyTable]);
|
||||
|
||||
this._connectionStatusLoader = this._view.modelBuilder.loadingComponent().withItem(
|
||||
statusContainer
|
||||
).withProps({
|
||||
loading: false
|
||||
}).component();
|
||||
this._connectionStatusLoader = this._view.modelBuilder.loadingComponent()
|
||||
.withItem(statusContainer)
|
||||
.withProps({ loading: false })
|
||||
.component();
|
||||
|
||||
container.addItems(
|
||||
[
|
||||
connectionLabelContainer,
|
||||
this._connectionStatusLoader
|
||||
]
|
||||
);
|
||||
container.addItems([
|
||||
connectionLabelContainer,
|
||||
this._connectionStatusLoader]);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
public async loadResourceGroupDropdown(): Promise<void> {
|
||||
this._resourceGroupDropdown.loading = true;
|
||||
this._dmsDropdown.loading = true;
|
||||
try {
|
||||
this.migrationStateModel._sqlMigrationServices = await utils.getAzureSqlMigrationServices(this.migrationStateModel._azureAccount, this.migrationStateModel._targetSubscription);
|
||||
this.migrationStateModel._resourceGroups = await utils.getSqlMigrationServiceResourceGroups(this.migrationStateModel._sqlMigrationServices, this.migrationStateModel._location);
|
||||
this._resourceGroupDropdown.values = await utils.getAzureResourceGroupsDropdownValues(this.migrationStateModel._resourceGroups);
|
||||
const resourceGroup = (this.migrationStateModel._sqlMigrationService)
|
||||
this._resourceGroupDropdown.loading = true;
|
||||
this._dmsDropdown.loading = true;
|
||||
|
||||
this.migrationStateModel._sqlMigrationServices = await utils.getAzureSqlMigrationServices(
|
||||
this.migrationStateModel._azureAccount,
|
||||
this.migrationStateModel._targetSubscription);
|
||||
|
||||
this.migrationStateModel._resourceGroups = utils.getServiceResourceGroupsByLocation(
|
||||
this.migrationStateModel._sqlMigrationServices,
|
||||
this.migrationStateModel._location);
|
||||
|
||||
this._resourceGroupDropdown.values = utils.getResourceDropdownValues(
|
||||
this.migrationStateModel._resourceGroups,
|
||||
constants.RESOURCE_GROUP_NOT_FOUND);
|
||||
|
||||
const resourceGroup = this.migrationStateModel._sqlMigrationService
|
||||
? getFullResourceGroupFromId(this.migrationStateModel._sqlMigrationService?.id)
|
||||
: undefined;
|
||||
utils.selectDefaultDropdownValue(this._resourceGroupDropdown, resourceGroup, false);
|
||||
} finally {
|
||||
this._dmsDropdown.loading = false;
|
||||
this._resourceGroupDropdown.loading = false;
|
||||
this._dmsDropdown.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
public async populateDms(): Promise<void> {
|
||||
this._dmsDropdown.loading = true;
|
||||
public populateDms(): void {
|
||||
try {
|
||||
this._dmsDropdown.values = await utils.getAzureSqlMigrationServicesDropdownValues(this.migrationStateModel._sqlMigrationServices, this.migrationStateModel._location, this.migrationStateModel._sqlMigrationServiceResourceGroup);
|
||||
utils.selectDefaultDropdownValue(this._dmsDropdown, this.migrationStateModel._sqlMigrationService?.id, false);
|
||||
this._dmsDropdown.loading = true;
|
||||
this._dmsDropdown.values = utils.getAzureResourceDropdownValues(
|
||||
this.migrationStateModel._sqlMigrationServices,
|
||||
this.migrationStateModel._location,
|
||||
this.migrationStateModel._sqlMigrationServiceResourceGroup.name,
|
||||
constants.SQL_MIGRATION_SERVICE_NOT_FOUND_ERROR);
|
||||
|
||||
utils.selectDefaultDropdownValue(
|
||||
this._dmsDropdown,
|
||||
this.migrationStateModel._sqlMigrationService?.id,
|
||||
false);
|
||||
} finally {
|
||||
this._dmsDropdown.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async loadMigrationServiceStatus(): Promise<void> {
|
||||
this._statusLoadingComponent.loading = true;
|
||||
try {
|
||||
await this.loadStatus();
|
||||
} catch (error) {
|
||||
logError(TelemetryViews.MigrationWizardIntegrationRuntimePage, 'ErrorLoadingMigrationServiceStatus', error);
|
||||
} finally {
|
||||
this._statusLoadingComponent.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async loadStatus(): Promise<void> {
|
||||
try {
|
||||
this._statusLoadingComponent.loading = true;
|
||||
|
||||
if (this.migrationStateModel._sqlMigrationService) {
|
||||
const migrationService = await getSqlMigrationService(
|
||||
this.migrationStateModel._azureAccount,
|
||||
@@ -436,12 +439,15 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
const state = migrationService.properties.integrationRuntimeState;
|
||||
if (state === 'Online') {
|
||||
await this._dmsStatusInfoBox.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.SERVICE_READY(this.migrationStateModel._sqlMigrationService!.name, this.migrationStateModel._nodeNames.join(', ')),
|
||||
text: constants.SERVICE_READY(
|
||||
this.migrationStateModel._sqlMigrationService!.name,
|
||||
this.migrationStateModel._nodeNames.join(', ')),
|
||||
style: 'success'
|
||||
});
|
||||
} else {
|
||||
await this._dmsStatusInfoBox.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.SERVICE_NOT_READY(this.migrationStateModel._sqlMigrationService!.name),
|
||||
text: constants.SERVICE_NOT_READY(
|
||||
this.migrationStateModel._sqlMigrationService!.name),
|
||||
style: 'error'
|
||||
});
|
||||
}
|
||||
@@ -464,65 +470,49 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
.withItems([this._copy2, this._refresh2])
|
||||
.component()
|
||||
}
|
||||
]
|
||||
];
|
||||
]];
|
||||
|
||||
await this._authKeyTable.setDataValues(data);
|
||||
}
|
||||
} catch (e) {
|
||||
logError(TelemetryViews.IntegrationRuntimePage, 'ErrorLoadingStatus', e);
|
||||
} finally {
|
||||
this._statusLoadingComponent.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createAuthenticationKeyTable(view: azdata.ModelView,): azdata.DeclarativeTableComponent {
|
||||
const authKeyTable = view.modelBuilder.declarativeTable().withProps({
|
||||
ariaLabel: constants.DATABASE_MIGRATION_SERVICE_AUTHENTICATION_KEYS,
|
||||
columns: [
|
||||
{
|
||||
displayName: constants.NAME,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '50px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
...styles.BODY_CSS
|
||||
const authKeyTable = view.modelBuilder.declarativeTable()
|
||||
.withProps({
|
||||
ariaLabel: constants.DATABASE_MIGRATION_SERVICE_AUTHENTICATION_KEYS,
|
||||
columns: [
|
||||
{
|
||||
displayName: constants.NAME,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '50px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: { ...styles.BODY_CSS },
|
||||
headerCssStyles: { ...styles.BODY_CSS, 'font-weight': '600' }
|
||||
},
|
||||
headerCssStyles: {
|
||||
...styles.BODY_CSS,
|
||||
'font-weight': '600'
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: constants.AUTH_KEY_COLUMN_HEADER,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '500px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
...styles.BODY_CSS,
|
||||
|
||||
{
|
||||
displayName: constants.AUTH_KEY_COLUMN_HEADER,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '500px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: { ...styles.BODY_CSS },
|
||||
headerCssStyles: { ...styles.BODY_CSS, 'font-weight': '600' }
|
||||
},
|
||||
headerCssStyles: {
|
||||
...styles.BODY_CSS,
|
||||
'font-weight': '600'
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '30px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: { ...styles.BODY_CSS },
|
||||
headerCssStyles: { ...styles.BODY_CSS }
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '30px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
...styles.BODY_CSS
|
||||
},
|
||||
headerCssStyles: {
|
||||
...styles.BODY_CSS
|
||||
}
|
||||
}
|
||||
],
|
||||
CSSStyles: {
|
||||
'margin-top': '5px',
|
||||
'width': WIZARD_INPUT_COMPONENT_WIDTH
|
||||
}
|
||||
}).component();
|
||||
],
|
||||
CSSStyles: { 'margin-top': '5px', 'width': WIZARD_INPUT_COMPONENT_WIDTH }
|
||||
}).component();
|
||||
return authKeyTable;
|
||||
}
|
||||
|
||||
@@ -6,17 +6,22 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationMode, MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
|
||||
import { MigrationMode, MigrationStateModel, MigrationTargetType, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../constants/strings';
|
||||
import * as styles from '../constants/styles';
|
||||
|
||||
export class MigrationModePage extends MigrationWizardPage {
|
||||
private _view!: azdata.ModelView;
|
||||
private originalMigrationMode!: MigrationMode;
|
||||
private _onlineButton!: azdata.RadioButtonComponent;
|
||||
private _offlineButton!: azdata.RadioButtonComponent;
|
||||
private _originalMigrationMode!: MigrationMode;
|
||||
private _disposables: vscode.Disposable[] = [];
|
||||
|
||||
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
|
||||
super(wizard, azdata.window.createWizardPage(constants.DATABASE_BACKUP_MIGRATION_MODE_LABEL, 'MigrationModePage'), migrationStateModel);
|
||||
super(
|
||||
wizard,
|
||||
azdata.window.createWizardPage(constants.DATABASE_BACKUP_MIGRATION_MODE_LABEL, 'MigrationModePage'),
|
||||
migrationStateModel);
|
||||
this.migrationStateModel._databaseBackup.migrationMode = this.migrationStateModel._databaseBackup.migrationMode || MigrationMode.ONLINE;
|
||||
}
|
||||
|
||||
@@ -25,115 +30,103 @@ export class MigrationModePage extends MigrationWizardPage {
|
||||
|
||||
const pageDescription = {
|
||||
title: '',
|
||||
component: view.modelBuilder.text().withProps({
|
||||
value: constants.DATABASE_BACKUP_MIGRATION_MODE_DESCRIPTION,
|
||||
CSSStyles: {
|
||||
...styles.BODY_CSS,
|
||||
'margin': '0'
|
||||
}
|
||||
}).component()
|
||||
component: view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_MIGRATION_MODE_DESCRIPTION,
|
||||
CSSStyles: { ...styles.BODY_CSS, 'margin': '0' }
|
||||
}).component()
|
||||
};
|
||||
|
||||
const form = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[
|
||||
pageDescription,
|
||||
this.migrationModeContainer(),
|
||||
]
|
||||
).withProps({
|
||||
CSSStyles: {
|
||||
'padding-top': '0'
|
||||
}
|
||||
}).component();
|
||||
.withFormItems([
|
||||
pageDescription,
|
||||
this.migrationModeContainer()])
|
||||
.withProps({ CSSStyles: { 'padding-top': '0' } })
|
||||
.component();
|
||||
|
||||
this._disposables.push(
|
||||
this._view.onClosed(
|
||||
e => this._disposables.forEach(
|
||||
d => { try { d.dispose(); } catch { } })));
|
||||
|
||||
this._disposables.push(this._view.onClosed(e => {
|
||||
this._disposables.forEach(
|
||||
d => { try { d.dispose(); } catch { } });
|
||||
}));
|
||||
await view.initializeModel(form);
|
||||
}
|
||||
|
||||
public async onPageEnter(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
|
||||
this.originalMigrationMode = this.migrationStateModel._databaseBackup.migrationMode;
|
||||
this.wizard.registerNavigationValidator((e) => {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
public async onPageLeave(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
|
||||
if (this.originalMigrationMode !== this.migrationStateModel._databaseBackup.migrationMode) {
|
||||
this.migrationStateModel.refreshDatabaseBackupPage = true;
|
||||
if (pageChangeInfo.newPage < pageChangeInfo.lastPage) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.wizard.registerNavigationValidator((e) => {
|
||||
return true;
|
||||
});
|
||||
const isSqlDbTarget = this.migrationStateModel._targetType === MigrationTargetType.SQLDB;
|
||||
this._onlineButton.enabled = !isSqlDbTarget;
|
||||
if (isSqlDbTarget) {
|
||||
this.migrationStateModel._databaseBackup.migrationMode = MigrationMode.OFFLINE;
|
||||
this._offlineButton.checked = true;
|
||||
await this._offlineButton.focus();
|
||||
}
|
||||
this._originalMigrationMode = this.migrationStateModel._databaseBackup.migrationMode;
|
||||
this.wizard.registerNavigationValidator((e) => true);
|
||||
}
|
||||
|
||||
public async onPageLeave(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
|
||||
if (this._originalMigrationMode !== this.migrationStateModel._databaseBackup.migrationMode) {
|
||||
this.migrationStateModel.refreshDatabaseBackupPage = true;
|
||||
}
|
||||
this.wizard.registerNavigationValidator((e) => true);
|
||||
}
|
||||
|
||||
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
|
||||
}
|
||||
|
||||
private migrationModeContainer(): azdata.FormComponent {
|
||||
const buttonGroup = 'migrationMode';
|
||||
this._onlineButton = this._view.modelBuilder.radioButton()
|
||||
.withProps({
|
||||
label: constants.DATABASE_BACKUP_MIGRATION_MODE_ONLINE_LABEL,
|
||||
name: buttonGroup,
|
||||
checked: this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.ONLINE,
|
||||
CSSStyles: { ...styles.LABEL_CSS, },
|
||||
}).component();
|
||||
const onlineDescription = this._view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_MIGRATION_MODE_ONLINE_DESCRIPTION,
|
||||
CSSStyles: { ...styles.NOTE_CSS, 'margin-left': '20px' }
|
||||
}).component();
|
||||
this._disposables.push(
|
||||
this._onlineButton.onDidChangeCheckedState(checked => {
|
||||
if (checked) {
|
||||
this.migrationStateModel._databaseBackup.migrationMode = MigrationMode.ONLINE;
|
||||
}
|
||||
}));
|
||||
|
||||
const onlineButton = this._view.modelBuilder.radioButton().withProps({
|
||||
label: constants.DATABASE_BACKUP_MIGRATION_MODE_ONLINE_LABEL,
|
||||
name: buttonGroup,
|
||||
checked: this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.ONLINE,
|
||||
CSSStyles: {
|
||||
...styles.LABEL_CSS,
|
||||
},
|
||||
}).component();
|
||||
this._offlineButton = this._view.modelBuilder.radioButton()
|
||||
.withProps({
|
||||
label: constants.DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_LABEL,
|
||||
name: buttonGroup,
|
||||
checked: this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE,
|
||||
CSSStyles: { ...styles.LABEL_CSS, 'margin-top': '12px' },
|
||||
}).component();
|
||||
const offlineDescription = this._view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_DESCRIPTION,
|
||||
CSSStyles: { ...styles.NOTE_CSS, 'margin-left': '20px' }
|
||||
}).component();
|
||||
this._disposables.push(
|
||||
this._offlineButton.onDidChangeCheckedState(checked => {
|
||||
if (checked) {
|
||||
this.migrationStateModel._databaseBackup.migrationMode = MigrationMode.OFFLINE;
|
||||
}
|
||||
}));
|
||||
|
||||
const onlineDescription = this._view.modelBuilder.text().withProps({
|
||||
value: constants.DATABASE_BACKUP_MIGRATION_MODE_ONLINE_DESCRIPTION,
|
||||
CSSStyles: {
|
||||
...styles.NOTE_CSS,
|
||||
'margin-left': '20px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
this._disposables.push(onlineButton.onDidChangeCheckedState((e) => {
|
||||
if (e) {
|
||||
this.migrationStateModel._databaseBackup.migrationMode = MigrationMode.ONLINE;
|
||||
}
|
||||
}));
|
||||
|
||||
const offlineButton = this._view.modelBuilder.radioButton().withProps({
|
||||
label: constants.DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_LABEL,
|
||||
name: buttonGroup,
|
||||
checked: this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE,
|
||||
CSSStyles: {
|
||||
...styles.LABEL_CSS,
|
||||
'margin-top': '12px'
|
||||
},
|
||||
}).component();
|
||||
|
||||
const offlineDescription = this._view.modelBuilder.text().withProps({
|
||||
value: constants.DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_DESCRIPTION,
|
||||
CSSStyles: {
|
||||
...styles.NOTE_CSS,
|
||||
'margin-left': '20px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
this._disposables.push(offlineButton.onDidChangeCheckedState((e) => {
|
||||
if (e) {
|
||||
this.migrationStateModel._databaseBackup.migrationMode = MigrationMode.OFFLINE;
|
||||
}
|
||||
}));
|
||||
|
||||
const flexContainer = this._view.modelBuilder.flexContainer().withItems(
|
||||
[
|
||||
onlineButton,
|
||||
const flexContainer = this._view.modelBuilder.flexContainer()
|
||||
.withItems([
|
||||
this._onlineButton,
|
||||
onlineDescription,
|
||||
offlineButton,
|
||||
offlineDescription
|
||||
]
|
||||
).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
this._offlineButton,
|
||||
offlineDescription]
|
||||
).withLayout({ flexFlow: 'column' })
|
||||
.component();
|
||||
|
||||
return {
|
||||
component: flexContainer
|
||||
};
|
||||
return { component: flexContainer };
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationSourceAuthenticationType, MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../constants/strings';
|
||||
import { createLabelTextComponent, createHeadingTextComponent, WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
||||
import { AuthenticationType } from '../api/sqlUtils';
|
||||
|
||||
export class SqlSourceConfigurationPage extends MigrationWizardPage {
|
||||
private _view!: azdata.ModelView;
|
||||
@@ -59,10 +60,13 @@ export class SqlSourceConfigurationPage extends MigrationWizardPage {
|
||||
const query = 'select SUSER_NAME()';
|
||||
const results = await queryProvider.runQueryAndReturn(await (azdata.connection.getUriForConnection(this.migrationStateModel.sourceConnectionId)), query);
|
||||
const username = results.rows[0][0].displayValue;
|
||||
this.migrationStateModel._authenticationType = connectionProfile.authenticationType === 'SqlLogin' ? MigrationSourceAuthenticationType.Sql : connectionProfile.authenticationType === 'Integrated' ? MigrationSourceAuthenticationType.Integrated : undefined!;
|
||||
this.migrationStateModel._authenticationType = connectionProfile.authenticationType === AuthenticationType.SqlLogin
|
||||
? MigrationSourceAuthenticationType.Sql
|
||||
: connectionProfile.authenticationType === AuthenticationType.Integrated
|
||||
? MigrationSourceAuthenticationType.Integrated
|
||||
: undefined!;
|
||||
|
||||
const sourceCredText = await createHeadingTextComponent(this._view, constants.SOURCE_CREDENTIALS);
|
||||
|
||||
const enterYourCredText = createLabelTextComponent(
|
||||
this._view,
|
||||
constants.ENTER_YOUR_SQL_CREDS,
|
||||
|
||||
@@ -24,134 +24,204 @@ export class SummaryPage extends MigrationWizardPage {
|
||||
|
||||
protected async registerContent(view: azdata.ModelView): Promise<void> {
|
||||
this._view = view;
|
||||
this._flexContainer = view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
this._flexContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({ flexFlow: 'column' })
|
||||
.component();
|
||||
const form = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[
|
||||
{
|
||||
component: this._flexContainer
|
||||
}
|
||||
]
|
||||
);
|
||||
.withFormItems([{ component: this._flexContainer }])
|
||||
.component();
|
||||
|
||||
this._disposables.push(this._view.onClosed(e => {
|
||||
this._disposables.forEach(
|
||||
d => { try { d.dispose(); } catch { } });
|
||||
}));
|
||||
this._disposables.push(
|
||||
this._view.onClosed(e =>
|
||||
this._disposables.forEach(
|
||||
d => { try { d.dispose(); } catch { } })));
|
||||
|
||||
await view.initializeModel(form.component());
|
||||
await view.initializeModel(form);
|
||||
}
|
||||
|
||||
public async onPageEnter(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
|
||||
const targetDatabaseSummary = new TargetDatabaseSummaryDialog(this.migrationStateModel);
|
||||
const targetDatabaseHyperlink = this._view.modelBuilder.hyperlink().withProps({
|
||||
url: '',
|
||||
label: this.migrationStateModel._databasesForMigration?.length.toString(),
|
||||
CSSStyles: {
|
||||
...styles.BODY_CSS,
|
||||
'margin': '0px',
|
||||
'width': '300px',
|
||||
}
|
||||
}).component();
|
||||
const isSqlVmTarget = this.migrationStateModel._targetType === MigrationTargetType.SQLVM;
|
||||
const isSqlMiTarget = this.migrationStateModel._targetType === MigrationTargetType.SQLMI;
|
||||
const isSqlDbTarget = this.migrationStateModel._targetType === MigrationTargetType.SQLDB;
|
||||
const isNetworkShare = this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE;
|
||||
|
||||
this._disposables.push(targetDatabaseHyperlink.onDidClick(async e => {
|
||||
await targetDatabaseSummary.initialize();
|
||||
}));
|
||||
const targetDatabaseHyperlink = this._view.modelBuilder.hyperlink()
|
||||
.withProps({
|
||||
url: '',
|
||||
label: (this.migrationStateModel._databasesForMigration?.length ?? 0).toString(),
|
||||
CSSStyles: { ...styles.BODY_CSS, 'margin': '0px', 'width': '300px', }
|
||||
}).component();
|
||||
|
||||
this._disposables.push(
|
||||
targetDatabaseHyperlink.onDidClick(
|
||||
async e => await targetDatabaseSummary.initialize()));
|
||||
|
||||
const targetDatabaseRow = this._view.modelBuilder.flexContainer()
|
||||
.withLayout(
|
||||
{
|
||||
flexFlow: 'row',
|
||||
alignItems: 'center',
|
||||
})
|
||||
.withItems(
|
||||
[
|
||||
createLabelTextComponent(this._view, constants.SUMMARY_DATABASE_COUNT_LABEL,
|
||||
{
|
||||
...styles.BODY_CSS,
|
||||
'width': '300px',
|
||||
}
|
||||
),
|
||||
targetDatabaseHyperlink
|
||||
],
|
||||
{
|
||||
CSSStyles: {
|
||||
'margin-right': '5px'
|
||||
}
|
||||
})
|
||||
.withLayout({ flexFlow: 'row', alignItems: 'center', })
|
||||
.withItems([
|
||||
createLabelTextComponent(
|
||||
this._view,
|
||||
constants.SUMMARY_DATABASE_COUNT_LABEL,
|
||||
{ ...styles.BODY_CSS, 'width': '300px' }),
|
||||
targetDatabaseHyperlink],
|
||||
{ CSSStyles: { 'margin-right': '5px' } })
|
||||
.component();
|
||||
|
||||
this._flexContainer.addItems(
|
||||
[
|
||||
await createHeadingTextComponent(this._view, constants.ACCOUNTS_SELECTION_PAGE_TITLE, true),
|
||||
createInformationRow(this._view, constants.ACCOUNTS_SELECTION_PAGE_TITLE, this.migrationStateModel._azureAccount.displayInfo.displayName),
|
||||
|
||||
await createHeadingTextComponent(this._view, constants.SOURCE_DATABASES),
|
||||
this._flexContainer
|
||||
.addItems([
|
||||
await createHeadingTextComponent(
|
||||
this._view,
|
||||
constants.SOURCE_DATABASES),
|
||||
targetDatabaseRow,
|
||||
|
||||
await createHeadingTextComponent(this._view, constants.AZURE_SQL_TARGET_PAGE_TITLE),
|
||||
createInformationRow(this._view, constants.AZURE_SQL_TARGET_PAGE_TITLE, (this.migrationStateModel._targetType === MigrationTargetType.SQLVM) ? constants.SUMMARY_VM_TYPE : constants.SUMMARY_MI_TYPE),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name),
|
||||
createInformationRow(this._view, constants.LOCATION, await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.location)),
|
||||
createInformationRow(this._view, constants.RESOURCE_GROUP, getResourceGroupFromId(this.migrationStateModel._targetServerInstance.id)),
|
||||
createInformationRow(this._view, (this.migrationStateModel._targetType === MigrationTargetType.SQLVM) ? constants.SUMMARY_VM_TYPE : constants.SUMMARY_MI_TYPE, await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.name!)),
|
||||
await createHeadingTextComponent(
|
||||
this._view,
|
||||
constants.AZURE_SQL_TARGET_PAGE_TITLE),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.ACCOUNTS_SELECTION_PAGE_TITLE,
|
||||
this.migrationStateModel._azureAccount.displayInfo.displayName),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.AZURE_SQL_TARGET_PAGE_TITLE,
|
||||
isSqlVmTarget
|
||||
? constants.SUMMARY_VM_TYPE
|
||||
: isSqlMiTarget
|
||||
? constants.SUMMARY_MI_TYPE
|
||||
: constants.SUMMARY_SQLDB_TYPE),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.SUBSCRIPTION,
|
||||
this.migrationStateModel._targetSubscription.name),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.LOCATION,
|
||||
await this.migrationStateModel.getLocationDisplayName(
|
||||
this.migrationStateModel._targetServerInstance.location)),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.RESOURCE_GROUP,
|
||||
getResourceGroupFromId(
|
||||
this.migrationStateModel._targetServerInstance.id)),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
(isSqlVmTarget)
|
||||
? constants.SUMMARY_VM_TYPE
|
||||
: (isSqlMiTarget)
|
||||
? constants.SUMMARY_MI_TYPE
|
||||
: constants.SUMMARY_SQLDB_TYPE,
|
||||
await this.migrationStateModel.getLocationDisplayName(
|
||||
this.migrationStateModel._targetServerInstance.name!)),
|
||||
await createHeadingTextComponent(
|
||||
this._view,
|
||||
constants.DATABASE_BACKUP_MIGRATION_MODE_LABEL),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.MODE,
|
||||
this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.ONLINE
|
||||
? constants.DATABASE_BACKUP_MIGRATION_MODE_ONLINE_LABEL
|
||||
: constants.DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_LABEL),
|
||||
]);
|
||||
|
||||
await createHeadingTextComponent(this._view, constants.DATABASE_BACKUP_MIGRATION_MODE_LABEL),
|
||||
createInformationRow(this._view, constants.MODE, this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.ONLINE ? constants.DATABASE_BACKUP_MIGRATION_MODE_ONLINE_LABEL : constants.DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_LABEL),
|
||||
if (this.migrationStateModel._targetType !== MigrationTargetType.SQLDB) {
|
||||
this._flexContainer.addItems([
|
||||
await createHeadingTextComponent(
|
||||
this._view,
|
||||
constants.DATABASE_BACKUP_PAGE_TITLE),
|
||||
await this.createNetworkContainerRows()]);
|
||||
}
|
||||
|
||||
await createHeadingTextComponent(this._view, constants.DATABASE_BACKUP_PAGE_TITLE),
|
||||
await this.createNetworkContainerRows(),
|
||||
this._flexContainer.addItems([
|
||||
|
||||
await createHeadingTextComponent(this._view, constants.IR_PAGE_TITLE),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name),
|
||||
createInformationRow(this._view, constants.LOCATION, await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._sqlMigrationService?.location!)),
|
||||
createInformationRow(this._view, constants.RESOURCE_GROUP, this.migrationStateModel._sqlMigrationService?.properties?.resourceGroup!),
|
||||
createInformationRow(this._view, constants.IR_PAGE_TITLE, this.migrationStateModel._sqlMigrationService?.name!)
|
||||
]
|
||||
);
|
||||
|
||||
if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE && this.migrationStateModel._nodeNames?.length > 0) {
|
||||
this._flexContainer.addItem(createInformationRow(this._view, constants.SHIR, this.migrationStateModel._nodeNames.join(', ')));
|
||||
await createHeadingTextComponent(
|
||||
this._view,
|
||||
constants.IR_PAGE_TITLE),
|
||||
createInformationRow(
|
||||
this._view, constants.SUBSCRIPTION,
|
||||
this.migrationStateModel._targetSubscription.name),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.LOCATION,
|
||||
await this.migrationStateModel.getLocationDisplayName(
|
||||
this.migrationStateModel._sqlMigrationService?.location!)),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.RESOURCE_GROUP,
|
||||
this.migrationStateModel._sqlMigrationService?.properties?.resourceGroup!),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.IR_PAGE_TITLE,
|
||||
this.migrationStateModel._sqlMigrationService?.name!)]);
|
||||
|
||||
if (isSqlDbTarget ||
|
||||
(isNetworkShare && this.migrationStateModel._nodeNames?.length > 0)) {
|
||||
|
||||
this._flexContainer.addItem(
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.SHIR,
|
||||
this.migrationStateModel._nodeNames.join(', ')));
|
||||
}
|
||||
}
|
||||
|
||||
public async onPageLeave(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
|
||||
this._flexContainer.clearItems();
|
||||
this.wizard.registerNavigationValidator(async (pageChangeInfo) => {
|
||||
return true;
|
||||
});
|
||||
this.wizard.registerNavigationValidator(async (pageChangeInfo) => true);
|
||||
}
|
||||
|
||||
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
|
||||
}
|
||||
|
||||
private async createNetworkContainerRows(): Promise<azdata.FlexContainer> {
|
||||
const flexContainer = this._view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
const flexContainer = this._view.modelBuilder.flexContainer()
|
||||
.withLayout({ flexFlow: 'column' })
|
||||
.component();
|
||||
|
||||
const networkShare = this.migrationStateModel._databaseBackup.networkShares[0];
|
||||
switch (this.migrationStateModel._databaseBackup.networkContainerType) {
|
||||
case NetworkContainerType.NETWORK_SHARE:
|
||||
flexContainer.addItems(
|
||||
[
|
||||
createInformationRow(this._view, constants.BACKUP_LOCATION, constants.NETWORK_SHARE),
|
||||
createInformationRow(this._view, constants.USER_ACCOUNT, this.migrationStateModel._databaseBackup.networkShares[0].windowsUser),
|
||||
await createHeadingTextComponent(this._view, constants.AZURE_STORAGE_ACCOUNT_TO_UPLOAD_BACKUPS),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._databaseBackup.subscription.name),
|
||||
createInformationRow(this._view, constants.LOCATION, this.migrationStateModel._databaseBackup.networkShares[0].storageAccount?.location),
|
||||
createInformationRow(this._view, constants.RESOURCE_GROUP, this.migrationStateModel._databaseBackup.networkShares[0].storageAccount?.resourceGroup!),
|
||||
createInformationRow(this._view, constants.STORAGE_ACCOUNT, this.migrationStateModel._databaseBackup.networkShares[0].storageAccount?.name!),
|
||||
]
|
||||
);
|
||||
flexContainer.addItems([
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.BACKUP_LOCATION,
|
||||
constants.NETWORK_SHARE),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.USER_ACCOUNT,
|
||||
networkShare.windowsUser),
|
||||
await createHeadingTextComponent(
|
||||
this._view,
|
||||
constants.AZURE_STORAGE_ACCOUNT_TO_UPLOAD_BACKUPS),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.SUBSCRIPTION,
|
||||
this.migrationStateModel._databaseBackup.subscription.name),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.LOCATION,
|
||||
networkShare.storageAccount?.location),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.RESOURCE_GROUP,
|
||||
networkShare.storageAccount?.resourceGroup!),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.STORAGE_ACCOUNT,
|
||||
networkShare.storageAccount?.name!),
|
||||
]);
|
||||
break;
|
||||
case NetworkContainerType.BLOB_CONTAINER:
|
||||
flexContainer.addItems(
|
||||
[
|
||||
createInformationRow(this._view, constants.TYPE, constants.BLOB_CONTAINER),
|
||||
createInformationRow(this._view, constants.SUMMARY_AZURE_STORAGE_SUBSCRIPTION, this.migrationStateModel._databaseBackup.subscription.name)
|
||||
]
|
||||
);
|
||||
flexContainer.addItems([
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.TYPE,
|
||||
constants.BLOB_CONTAINER),
|
||||
createInformationRow(
|
||||
this._view,
|
||||
constants.SUMMARY_AZURE_STORAGE_SUBSCRIPTION,
|
||||
this.migrationStateModel._databaseBackup.subscription.name)]);
|
||||
}
|
||||
return flexContainer;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@ import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews, logError
|
||||
import * as styles from '../constants/styles';
|
||||
import { MigrationLocalStorage, MigrationServiceContext } from '../models/migrationLocalStorage';
|
||||
import { azureResource } from 'azurecore';
|
||||
import { ServiceContextChangeEvent } from '../dashboard/tabBase';
|
||||
|
||||
export const WIZARD_INPUT_COMPONENT_WIDTH = '600px';
|
||||
export class WizardController {
|
||||
@@ -27,7 +28,7 @@ export class WizardController {
|
||||
constructor(
|
||||
private readonly extensionContext: vscode.ExtensionContext,
|
||||
private readonly _model: MigrationStateModel,
|
||||
private readonly _onClosedCallback: () => Promise<void>) {
|
||||
private readonly _serviceContextChangedEvent: vscode.EventEmitter<ServiceContextChangeEvent>) {
|
||||
}
|
||||
|
||||
public async openWizard(connectionId: string): Promise<void> {
|
||||
@@ -40,7 +41,11 @@ export class WizardController {
|
||||
|
||||
private async createWizard(stateModel: MigrationStateModel): Promise<void> {
|
||||
const serverName = (await stateModel.getSourceConnectionProfile()).serverName;
|
||||
this._wizardObject = azdata.window.createWizard(loc.WIZARD_TITLE(serverName), 'MigrationWizard', 'wide');
|
||||
this._wizardObject = azdata.window.createWizard(
|
||||
loc.WIZARD_TITLE(serverName),
|
||||
'MigrationWizard',
|
||||
'wide');
|
||||
|
||||
this._wizardObject.generateScriptButton.enabled = false;
|
||||
this._wizardObject.generateScriptButton.hidden = true;
|
||||
const saveAndCloseButton = azdata.window.createButton(loc.SAVE_AND_CLOSE);
|
||||
@@ -60,8 +65,7 @@ export class WizardController {
|
||||
migrationModePage,
|
||||
databaseBackupPage,
|
||||
integrationRuntimePage,
|
||||
summaryPage
|
||||
];
|
||||
summaryPage];
|
||||
|
||||
this._wizardObject.pages = pages.map(p => p.getwizardPage());
|
||||
|
||||
@@ -82,20 +86,26 @@ export class WizardController {
|
||||
|
||||
// if the user selected network share and selected save & close afterwards, it should always return to the database backup page so that
|
||||
// the user can input their password again
|
||||
if (this._model.savedInfo.closedPage >= Page.DatabaseBackup && this._model.savedInfo.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
if (this._model.savedInfo.closedPage >= Page.DatabaseBackup &&
|
||||
this._model.savedInfo.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
wizardSetupPromises.push(this._wizardObject.setCurrentPage(Page.DatabaseBackup));
|
||||
} else {
|
||||
wizardSetupPromises.push(this._wizardObject.setCurrentPage(this._model.savedInfo.closedPage));
|
||||
}
|
||||
}
|
||||
|
||||
this._model.extensionContext.subscriptions.push(this._wizardObject.onPageChanged(async (pageChangeInfo: azdata.window.WizardPageChangeInfo) => {
|
||||
const newPage = pageChangeInfo.newPage;
|
||||
const lastPage = pageChangeInfo.lastPage;
|
||||
this.sendPageButtonClickEvent(pageChangeInfo).catch(e => logError(TelemetryViews.MigrationWizardController, 'ErrorSendingPageButtonClick', e));
|
||||
await pages[lastPage]?.onPageLeave(pageChangeInfo);
|
||||
await pages[newPage]?.onPageEnter(pageChangeInfo);
|
||||
}));
|
||||
this._model.extensionContext.subscriptions.push(
|
||||
this._wizardObject.onPageChanged(
|
||||
async (pageChangeInfo: azdata.window.WizardPageChangeInfo) => {
|
||||
const newPage = pageChangeInfo.newPage;
|
||||
const lastPage = pageChangeInfo.lastPage;
|
||||
this.sendPageButtonClickEvent(pageChangeInfo)
|
||||
.catch(e => logError(
|
||||
TelemetryViews.MigrationWizardController,
|
||||
'ErrorSendingPageButtonClick', e));
|
||||
await pages[lastPage]?.onPageLeave(pageChangeInfo);
|
||||
await pages[newPage]?.onPageEnter(pageChangeInfo);
|
||||
}));
|
||||
|
||||
this._wizardObject.registerNavigationValidator(async validator => {
|
||||
// const lastPage = validator.lastPage;
|
||||
@@ -110,50 +120,59 @@ export class WizardController {
|
||||
await Promise.all(wizardSetupPromises);
|
||||
this._model.extensionContext.subscriptions.push(
|
||||
this._wizardObject.onPageChanged(
|
||||
async (pageChangeInfo: azdata.window.WizardPageChangeInfo) => {
|
||||
await pages[0].onPageEnter(pageChangeInfo);
|
||||
}));
|
||||
|
||||
this._disposables.push(saveAndCloseButton.onClick(async () => {
|
||||
await stateModel.saveInfo(serverName, this._wizardObject.currentPage);
|
||||
await this._wizardObject.close();
|
||||
|
||||
if (stateModel.performanceCollectionInProgress()) {
|
||||
void vscode.window.showInformationMessage(loc.SAVE_AND_CLOSE_POPUP);
|
||||
}
|
||||
}));
|
||||
|
||||
this._disposables.push(this._wizardObject.cancelButton.onClick(e => {
|
||||
sendSqlMigrationActionEvent(
|
||||
TelemetryViews.SqlMigrationWizard,
|
||||
TelemetryAction.PageButtonClick,
|
||||
{
|
||||
...this.getTelemetryProps(),
|
||||
'buttonPressed': TelemetryAction.Cancel,
|
||||
'pageTitle': this._wizardObject.pages[this._wizardObject.currentPage].title
|
||||
}, {});
|
||||
}));
|
||||
|
||||
this._wizardObject.doneButton.label = loc.START_MIGRATION_TEXT;
|
||||
async (pageChangeInfo: azdata.window.WizardPageChangeInfo) =>
|
||||
await pages[0].onPageEnter(pageChangeInfo)));
|
||||
|
||||
this._disposables.push(
|
||||
this._wizardObject.doneButton.onClick(async (e) => {
|
||||
await stateModel.startMigration();
|
||||
await this.updateServiceContext(stateModel);
|
||||
await this._onClosedCallback();
|
||||
saveAndCloseButton.onClick(async () => {
|
||||
await stateModel.saveInfo(serverName, this._wizardObject.currentPage);
|
||||
await this._wizardObject.close();
|
||||
|
||||
if (stateModel.performanceCollectionInProgress()) {
|
||||
void vscode.window.showInformationMessage(loc.SAVE_AND_CLOSE_POPUP);
|
||||
}
|
||||
}));
|
||||
|
||||
this._disposables.push(
|
||||
this._wizardObject.cancelButton.onClick(e => {
|
||||
sendSqlMigrationActionEvent(
|
||||
TelemetryViews.SqlMigrationWizard,
|
||||
TelemetryAction.PageButtonClick,
|
||||
{
|
||||
...this.getTelemetryProps(),
|
||||
'buttonPressed': TelemetryAction.Done,
|
||||
'buttonPressed': TelemetryAction.Cancel,
|
||||
'pageTitle': this._wizardObject.pages[this._wizardObject.currentPage].title
|
||||
}, {});
|
||||
},
|
||||
{});
|
||||
}));
|
||||
|
||||
this._wizardObject.doneButton.label = loc.START_MIGRATION_TEXT;
|
||||
|
||||
this._disposables.push(
|
||||
this._wizardObject.doneButton.onClick(async (e) => {
|
||||
try {
|
||||
await stateModel.startMigration();
|
||||
await this.updateServiceContext(stateModel, this._serviceContextChangedEvent);
|
||||
} catch (e) {
|
||||
logError(TelemetryViews.MigrationWizardController, 'StartMigrationFailed', e);
|
||||
} finally {
|
||||
sendSqlMigrationActionEvent(
|
||||
TelemetryViews.SqlMigrationWizard,
|
||||
TelemetryAction.PageButtonClick,
|
||||
{
|
||||
...this.getTelemetryProps(),
|
||||
'buttonPressed': TelemetryAction.Done,
|
||||
'pageTitle': this._wizardObject.pages[this._wizardObject.currentPage].title
|
||||
},
|
||||
{});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private async updateServiceContext(stateModel: MigrationStateModel): Promise<void> {
|
||||
private async updateServiceContext(
|
||||
stateModel: MigrationStateModel,
|
||||
serviceContextChangedEvent: vscode.EventEmitter<ServiceContextChangeEvent>): Promise<void> {
|
||||
|
||||
const resourceGroup = this._getResourceGroupByName(
|
||||
stateModel._resourceGroups,
|
||||
stateModel._sqlMigrationService?.properties.resourceGroup);
|
||||
@@ -174,18 +193,28 @@ export class WizardController {
|
||||
location: location,
|
||||
resourceGroup: resourceGroup,
|
||||
migrationService: stateModel._sqlMigrationService,
|
||||
});
|
||||
},
|
||||
serviceContextChangedEvent);
|
||||
}
|
||||
|
||||
private _getResourceGroupByName(resourceGroups: azureResource.AzureResourceResourceGroup[], displayName?: string): azureResource.AzureResourceResourceGroup | undefined {
|
||||
private _getResourceGroupByName(
|
||||
resourceGroups: azureResource.AzureResourceResourceGroup[],
|
||||
displayName?: string): azureResource.AzureResourceResourceGroup | undefined {
|
||||
|
||||
return resourceGroups.find(rg => rg.name === displayName);
|
||||
}
|
||||
|
||||
private _getLocationByValue(locations: azureResource.AzureLocation[], name?: string): azureResource.AzureLocation | undefined {
|
||||
private _getLocationByValue(
|
||||
locations: azureResource.AzureLocation[],
|
||||
name?: string): azureResource.AzureLocation | undefined {
|
||||
|
||||
return locations.find(loc => loc.name === name);
|
||||
}
|
||||
|
||||
private _getSubscriptionFromResourceId(subscriptions: azureResource.AzureResourceSubscription[], resourceId?: string): azureResource.AzureResourceSubscription | undefined {
|
||||
private _getSubscriptionFromResourceId(
|
||||
subscriptions: azureResource.AzureResourceSubscription[],
|
||||
resourceId?: string): azureResource.AzureResourceSubscription | undefined {
|
||||
|
||||
let parts = resourceId?.split('/subscriptions/');
|
||||
if (parts?.length && parts?.length > 1) {
|
||||
parts = parts[1]?.split('/resourcegroups/');
|
||||
@@ -198,7 +227,9 @@ export class WizardController {
|
||||
}
|
||||
|
||||
private async sendPageButtonClickEvent(pageChangeInfo: azdata.window.WizardPageChangeInfo) {
|
||||
const buttonPressed = pageChangeInfo.newPage > pageChangeInfo.lastPage ? TelemetryAction.Next : TelemetryAction.Prev;
|
||||
const buttonPressed = pageChangeInfo.newPage > pageChangeInfo.lastPage
|
||||
? TelemetryAction.Next
|
||||
: TelemetryAction.Prev;
|
||||
const pageTitle = this._wizardObject.pages[pageChangeInfo.lastPage]?.title;
|
||||
sendSqlMigrationActionEvent(
|
||||
TelemetryViews.SqlMigrationWizard,
|
||||
@@ -207,7 +238,8 @@ export class WizardController {
|
||||
...this.getTelemetryProps(),
|
||||
'buttonPressed': buttonPressed,
|
||||
'pageTitle': pageTitle
|
||||
}, {});
|
||||
},
|
||||
{});
|
||||
}
|
||||
|
||||
private getTelemetryProps() {
|
||||
@@ -221,33 +253,38 @@ export class WizardController {
|
||||
}
|
||||
}
|
||||
|
||||
export function createInformationRow(view: azdata.ModelView, label: string, value: string): azdata.FlexContainer {
|
||||
export function createInformationRow(
|
||||
view: azdata.ModelView,
|
||||
label: string,
|
||||
value: string): azdata.FlexContainer {
|
||||
|
||||
return view.modelBuilder.flexContainer()
|
||||
.withLayout(
|
||||
{
|
||||
flexFlow: 'row',
|
||||
alignItems: 'center',
|
||||
})
|
||||
.withItems(
|
||||
[
|
||||
createLabelTextComponent(view, label,
|
||||
{
|
||||
...styles.BODY_CSS,
|
||||
'margin': '4px 0px',
|
||||
'width': '300px',
|
||||
}
|
||||
),
|
||||
createTextComponent(view, value,
|
||||
{
|
||||
...styles.BODY_CSS,
|
||||
'margin': '4px 0px',
|
||||
'width': '300px',
|
||||
}
|
||||
)
|
||||
]).component();
|
||||
.withLayout({ flexFlow: 'row', alignItems: 'center', })
|
||||
.withItems([
|
||||
createLabelTextComponent(
|
||||
view,
|
||||
label,
|
||||
{
|
||||
...styles.BODY_CSS,
|
||||
'margin': '4px 0px',
|
||||
'width': '300px',
|
||||
}),
|
||||
createTextComponent(
|
||||
view,
|
||||
value,
|
||||
{
|
||||
...styles.BODY_CSS,
|
||||
'margin': '4px 0px',
|
||||
'width': '300px',
|
||||
})])
|
||||
.component();
|
||||
}
|
||||
|
||||
export async function createHeadingTextComponent(view: azdata.ModelView, value: string, firstElement: boolean = false): Promise<azdata.TextComponent> {
|
||||
export async function createHeadingTextComponent(
|
||||
view: azdata.ModelView,
|
||||
value: string,
|
||||
firstElement: boolean = false): Promise<azdata.TextComponent> {
|
||||
|
||||
const component = createTextComponent(view, value);
|
||||
await component.updateCssStyles({
|
||||
...styles.LABEL_CSS,
|
||||
@@ -256,14 +293,20 @@ export async function createHeadingTextComponent(view: azdata.ModelView, value:
|
||||
return component;
|
||||
}
|
||||
|
||||
export function createLabelTextComponent(view: azdata.ModelView, value: string, styles: { [key: string]: string; } = { 'width': '300px' }): azdata.TextComponent {
|
||||
const component = createTextComponent(view, value, styles);
|
||||
return component;
|
||||
export function createLabelTextComponent(
|
||||
view: azdata.ModelView,
|
||||
value: string,
|
||||
styles: { [key: string]: string; } = { 'width': '300px' }): azdata.TextComponent {
|
||||
|
||||
return createTextComponent(view, value, styles);
|
||||
}
|
||||
|
||||
export function createTextComponent(view: azdata.ModelView, value: string, styles: { [key: string]: string; } = { 'width': '300px' }): azdata.TextComponent {
|
||||
return view.modelBuilder.text().withProps({
|
||||
value: value,
|
||||
CSSStyles: styles
|
||||
}).component();
|
||||
export function createTextComponent(
|
||||
view: azdata.ModelView,
|
||||
value: string,
|
||||
styles: { [key: string]: string; } = { 'width': '300px' }): azdata.TextComponent {
|
||||
|
||||
return view.modelBuilder.text()
|
||||
.withProps({ value: value, CSSStyles: styles })
|
||||
.component();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user