From eb3598f1a7cd1bda93cfe5f7a636c1a84debef53 Mon Sep 17 00:00:00 2001 From: Siyang Yao Date: Wed, 11 Oct 2023 14:53:49 -0700 Subject: [PATCH] fix bugs (#24654) Co-authored-by: Siyang Yao --- extensions/sql-migration/src/api/utils.ts | 6 ++ .../sql-migration/src/constants/strings.ts | 2 +- .../restartMigrationDialog.ts | 3 +- .../sql-migration/src/models/stateMachine.ts | 7 +++ .../src/wizard/databaseSelectorPage.ts | 17 +++++- .../src/wizard/skuRecommendationPage.ts | 4 ++ .../src/wizard/targetSelectionPage.ts | 57 ++++++++++++++++--- 7 files changed, 85 insertions(+), 11 deletions(-) diff --git a/extensions/sql-migration/src/api/utils.ts b/extensions/sql-migration/src/api/utils.ts index ac5a63e6b99b..e7abbc8e085c 100644 --- a/extensions/sql-migration/src/api/utils.ts +++ b/extensions/sql-migration/src/api/utils.ts @@ -1169,3 +1169,9 @@ export async function clearDropDown(dropDown: DropDownComponent): Promise await dropDown.updateProperty('value', undefined); await dropDown.updateProperty('values', []); } + +export async function clearDropDownWithLoading(dropDown: DropDownComponent): Promise { + dropDown.loading = true; + await dropDown.updateProperty('value', undefined); + await dropDown.updateProperty('values', []); +} diff --git a/extensions/sql-migration/src/constants/strings.ts b/extensions/sql-migration/src/constants/strings.ts index f0967bc77606..c790b0804f0d 100644 --- a/extensions/sql-migration/src/constants/strings.ts +++ b/extensions/sql-migration/src/constants/strings.ts @@ -547,7 +547,7 @@ export function ACCOUNT_CREDENTIALS_REFRESH(accountName: string): string { "{0} (requires credentials refresh)", accountName); } -export const SELECT_SERVICE_PLACEHOLDER = localize('sql.migration.select.service.select.migration.target', "Select a target server."); +export const SELECT_SERVICE_PLACEHOLDER = localize('sql.migration.select.service.select.migration.target', "Select a target server"); // database backup page export const DATA_SOURCE_CONFIGURATION_PAGE_TITLE = localize('sql.migration.data.source.configuration.page.title', "Data source configuration"); diff --git a/extensions/sql-migration/src/dialog/restartMigration/restartMigrationDialog.ts b/extensions/sql-migration/src/dialog/restartMigration/restartMigrationDialog.ts index 2ab03461fc5b..b792af229496 100644 --- a/extensions/sql-migration/src/dialog/restartMigration/restartMigrationDialog.ts +++ b/extensions/sql-migration/src/dialog/restartMigration/restartMigrationDialog.ts @@ -75,7 +75,8 @@ export class RestartMigrationDialog { // Integration Runtime sqlMigrationService: serviceContext.migrationService, serviceSubscription: null, - serviceResourceGroup: null + serviceResourceGroup: null, + xEventsFilesFolderPath: null }; const getStorageAccountResourceGroup = (storageAccountResourceId: string): azureResource.AzureResourceResourceGroup => { diff --git a/extensions/sql-migration/src/models/stateMachine.ts b/extensions/sql-migration/src/models/stateMachine.ts index 4fec86f3de54..4a4a3f9bca75 100644 --- a/extensions/sql-migration/src/models/stateMachine.ts +++ b/extensions/sql-migration/src/models/stateMachine.ts @@ -153,6 +153,7 @@ export interface SavedInfo { serviceSubscription: azurecore.azureResource.AzureResourceSubscription | null; serviceResourceGroup: azurecore.azureResource.AzureResourceResourceGroup | null; serverAssessment: ServerAssessment | null; + xEventsFilesFolderPath: string | null; skuRecommendation: SkuRecommendationSavedInfo | null; } @@ -1257,6 +1258,7 @@ export class MigrationStateModel implements Model, vscode.Disposable { targetDatabaseNames: [], sqlMigrationService: undefined, serverAssessment: null, + xEventsFilesFolderPath: null, skuRecommendation: null, serviceResourceGroup: null, serviceSubscription: null, @@ -1288,6 +1290,7 @@ export class MigrationStateModel implements Model, vscode.Disposable { saveInfo.migrationTargetType = this._targetType; saveInfo.databaseList = this._databasesForMigration; saveInfo.serverAssessment = this._assessmentResults; + saveInfo.xEventsFilesFolderPath = this._xEventsFilesFolderPath; if (this._skuRecommendationPerformanceDataSource) { const skuRecommendation: SkuRecommendationSavedInfo = { @@ -1304,6 +1307,7 @@ export class MigrationStateModel implements Model, vscode.Disposable { case Page.DatabaseSelector: saveInfo.databaseAssessment = this._databasesForAssessment; + saveInfo.xEventsFilesFolderPath = this._xEventsFilesFolderPath; await this.extensionContext.globalState.update(`${this.mementoString}.${serverName}`, saveInfo); } } @@ -1350,6 +1354,9 @@ export class MigrationStateModel implements Model, vscode.Disposable { this._sqlMigrationServiceSubscription = this.savedInfo.serviceSubscription || undefined!; this._sqlMigrationServiceResourceGroup = this.savedInfo.serviceResourceGroup || undefined!; + this._assessedDatabaseList = this.savedInfo.databaseAssessment ?? []; + this._databasesForAssessment = this.savedInfo.databaseAssessment ?? []; + this._xEventsFilesFolderPath = this.savedInfo.xEventsFilesFolderPath ?? ''; const savedAssessmentResults = this.savedInfo.serverAssessment; if (savedAssessmentResults) { this._assessmentResults = savedAssessmentResults; diff --git a/extensions/sql-migration/src/wizard/databaseSelectorPage.ts b/extensions/sql-migration/src/wizard/databaseSelectorPage.ts index 918820a5628c..8f28446d3529 100644 --- a/extensions/sql-migration/src/wizard/databaseSelectorPage.ts +++ b/extensions/sql-migration/src/wizard/databaseSelectorPage.ts @@ -18,11 +18,12 @@ export class DatabaseSelectorPage extends MigrationWizardPage { private _databaseSelectorTable!: azdata.TableComponent; private _xEventsGroup!: azdata.GroupContainer; private _xEventsFolderPickerInput!: azdata.InputBoxComponent; - private _xEventsFilesFolderPath!: string; + private _xEventsFilesFolderPath: string = ''; private _dbNames!: string[]; private _dbCount!: azdata.TextComponent; private _databaseTableValues!: any[]; private _disposables: vscode.Disposable[] = []; + private _enableNavigationValidation: boolean = true; private readonly TABLE_WIDTH = 650; @@ -57,6 +58,12 @@ export class DatabaseSelectorPage extends MigrationWizardPage { if (pageChangeInfo.newPage < pageChangeInfo.lastPage) { return true; } + + if (!this._enableNavigationValidation) { + this._enableNavigationValidation = true; + return true; + } + if (this.selectedDbs().length === 0) { this.wizard.message = { text: constants.SELECT_DATABASE_TO_CONTINUE, @@ -67,6 +74,14 @@ export class DatabaseSelectorPage extends MigrationWizardPage { return true; }); + if (this.migrationStateModel.resumeAssessment) { + // if start a new session, it won't trigger navigation validator until clicking 'Next'. + // It works as expected if no target or databases are selected, it should show errors and block to next page. + // However, if resume the previously saved session, wizard.setCurrentPage will trigger wizard navigation validator without clicking 'Next'. + // At this moment, all components are not initialized yet. Therefore, _databaseSelectorTable is undefined, so selectedDbs().length is always 0. + this._enableNavigationValidation = false; + } + this._xEventsFilesFolderPath = this.migrationStateModel._xEventsFilesFolderPath; } diff --git a/extensions/sql-migration/src/wizard/skuRecommendationPage.ts b/extensions/sql-migration/src/wizard/skuRecommendationPage.ts index db957beb82e9..1af5d1b03621 100644 --- a/extensions/sql-migration/src/wizard/skuRecommendationPage.ts +++ b/extensions/sql-migration/src/wizard/skuRecommendationPage.ts @@ -654,6 +654,10 @@ export class SKURecommendationPage extends MigrationWizardPage { public async refreshCardText(showLoadingIcon: boolean = true): Promise { this._rbgLoader.loading = showLoadingIcon && true; + if (!this._rbg.selectedCardId) { + this._rbg.selectedCardId = MigrationTargetType.SQLMI; + } + switch (this._rbg.selectedCardId) { case MigrationTargetType.SQLMI: this.migrationStateModel._databasesForMigration = this.migrationStateModel._miDbs; diff --git a/extensions/sql-migration/src/wizard/targetSelectionPage.ts b/extensions/sql-migration/src/wizard/targetSelectionPage.ts index c1e5b3ba47d1..2ea2e77b645e 100644 --- a/extensions/sql-migration/src/wizard/targetSelectionPage.ts +++ b/extensions/sql-migration/src/wizard/targetSelectionPage.ts @@ -89,7 +89,7 @@ export class TargetSelectionPage extends MigrationWizardPage { { component: this._pageDescription }, { component: this.createAzureAccountsDropdown() }, { component: this.createAzureTenantContainer() }, - { component: this.createTargetDropdownContainer() }, + { component: await this.createTargetDropdownContainer() }, { component: this._certMigrationRequiredInfoBox } ]).withProps({ CSSStyles: { 'padding-top': '0' } @@ -271,6 +271,10 @@ export class TargetSelectionPage extends MigrationWizardPage { await this._targetPasswordInputBox.updateProperties({ required: isSqlDbTarget }); await utils.updateControlDisplay(this._resourceAuthenticationContainer, isSqlDbTarget); + if (!this._migrationTargetPlatform) { + this._migrationTargetPlatform = this.migrationStateModel._targetType; + } + if (this._migrationTargetPlatform !== this.migrationStateModel._targetType) { // if the user had previously selected values on this page, then went back to change the migration target platform // and came back, forcibly reload the location/resource group/resource values since they will now be different @@ -287,14 +291,19 @@ export class TargetSelectionPage extends MigrationWizardPage { await utils.clearDropDown(this._azureAccountsDropdown); await utils.clearDropDown(this._accountTenantDropdown); - await utils.clearDropDown(this._azureSubscriptionDropdown); - await utils.clearDropDown(this._azureLocationDropdown); - await utils.clearDropDown(this._azureResourceGroupDropdown); - await utils.clearDropDown(this._azureResourceDropdown); + await utils.clearDropDownWithLoading(this._azureSubscriptionDropdown); + await utils.clearDropDownWithLoading(this._azureLocationDropdown); + await utils.clearDropDownWithLoading(this._azureResourceGroupDropdown); + await utils.clearDropDownWithLoading(this._azureResourceDropdown); } await utils.updateControlDisplay(this._certMigrationRequiredInfoBox, this.migrationStateModel.tdeMigrationConfig.shouldAdsMigrateCertificates()); await this.populateAzureAccountsDropdown(); + await this.populateTenantsDropdown(); + await this.populateSubscriptionDropdown(); + await this.populateLocationDropdown(); + await this.populateResourceGroupDropdown(); + await this.populateResourceInstanceDropdown(); } public async onPageLeave(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise { @@ -403,7 +412,7 @@ export class TargetSelectionPage extends MigrationWizardPage { return this._accountTenantFlexContainer; } - private createTargetDropdownContainer(): azdata.FlexContainer { + private async createTargetDropdownContainer(): Promise { const subscriptionDropdownLabel = this._view.modelBuilder.text() .withProps({ value: constants.SUBSCRIPTION, @@ -474,6 +483,11 @@ export class TargetSelectionPage extends MigrationWizardPage { this._resourceSelectionContainer = this._createResourceDropdowns(); this._resourceAuthenticationContainer = this._createResourceAuthenticationContainer(); + const isSqlDbTarget = this.migrationStateModel._targetType === MigrationTargetType.SQLDB; + await this._targetUserNameInputBox.updateProperties({ required: isSqlDbTarget }); + await this._targetPasswordInputBox.updateProperties({ required: isSqlDbTarget }); + await utils.updateControlDisplay(this._resourceAuthenticationContainer, isSqlDbTarget); + return this._view.modelBuilder.flexContainer() .withItems([ subscriptionDropdownLabel, @@ -700,9 +714,13 @@ export class TargetSelectionPage extends MigrationWizardPage { await this.populateResourceInstanceDropdown(); })); + const resourceDropDownValue = this.migrationStateModel._targetType === MigrationTargetType.SQLMI + ? constants.AZURE_SQL_DATABASE_MANAGED_INSTANCE + : this.migrationStateModel._targetType === MigrationTargetType.SQLDB ? constants.AZURE_SQL_DATABASE : constants.AZURE_SQL_DATABASE_VIRTUAL_MACHINE; + this._azureResourceDropdownLabel = this._view.modelBuilder.text() .withProps({ - value: constants.AZURE_SQL_DATABASE_MANAGED_INSTANCE, + value: resourceDropDownValue, description: constants.TARGET_RESOURCE_INFO, width: WIZARD_INPUT_COMPONENT_WIDTH, requiredIndicator: true, @@ -710,7 +728,7 @@ export class TargetSelectionPage extends MigrationWizardPage { }).component(); this._azureResourceDropdown = this._view.modelBuilder.dropDown() .withProps({ - ariaLabel: constants.AZURE_SQL_DATABASE_MANAGED_INSTANCE, + ariaLabel: resourceDropDownValue, width: WIZARD_INPUT_COMPONENT_WIDTH, editable: true, required: true, @@ -910,6 +928,10 @@ export class TargetSelectionPage extends MigrationWizardPage { this._azureAccountsDropdown, accountId, false); + const selectedAccount = this.migrationStateModel._azureAccounts?.find(account => account.displayInfo.displayName === (this._azureAccountsDropdown.value)?.displayName); + this.migrationStateModel._azureAccount = (selectedAccount) + ? utils.deepClone(selectedAccount)! + : undefined!; } finally { this._azureAccountsDropdown.loading = false; } @@ -933,6 +955,10 @@ export class TargetSelectionPage extends MigrationWizardPage { tenantId, true); } + const selectedTenant = this.migrationStateModel._accountTenants?.find(tenant => tenant.displayName === (this._accountTenantDropdown.value)?.displayName); + this.migrationStateModel._azureTenant = selectedTenant + ? utils.deepClone(selectedTenant) + : undefined!; await this._azureAccountsDropdown.validate(); } finally { this._accountTenantDropdown.loading = false; @@ -960,6 +986,12 @@ export class TargetSelectionPage extends MigrationWizardPage { this._azureSubscriptionDropdown, subscriptionId, false); + const selectedSubscription = this.migrationStateModel._subscriptions?.find( + subscription => `${subscription.name} - ${subscription.id}` === (this._azureSubscriptionDropdown.value)?.displayName); + this.migrationStateModel._targetSubscription = (selectedSubscription) + ? utils.deepClone(selectedSubscription)! + : undefined!; + this.migrationStateModel.refreshDatabaseBackupPage = true; } catch (e) { console.log(e); } finally { @@ -1009,6 +1041,10 @@ export class TargetSelectionPage extends MigrationWizardPage { this._azureLocationDropdown, location, true); + const selectedLocation = this.migrationStateModel._locations?.find(location => location.displayName === (this._azureLocationDropdown.value)?.displayName); + this.migrationStateModel._location = (selectedLocation) + ? utils.deepClone(selectedLocation)! + : undefined!; } catch (e) { console.log(e); } finally { @@ -1047,6 +1083,11 @@ export class TargetSelectionPage extends MigrationWizardPage { this._azureResourceGroupDropdown, resourceGroupId, false); + + const selectedResourceGroup = this.migrationStateModel._resourceGroups?.find(rg => rg.name === (this._azureResourceGroupDropdown.value)?.displayName); + this.migrationStateModel._resourceGroup = (selectedResourceGroup) + ? utils.deepClone(selectedResourceGroup)! + : undefined!; } catch (e) { console.log(e); } finally {