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:
brian-harris
2022-08-19 18:12:34 -07:00
committed by GitHub
parent c0b09dcedd
commit 7a736b76fa
42 changed files with 5716 additions and 4209 deletions

View File

@@ -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;
}