public async onPageEnter()

in extensions/sql-migration/src/wizard/databaseBackupPage.ts [738:1109]


	public async onPageEnter(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise<void> {
		if (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup) {
			this.migrationStateModel._databaseBackup.networkContainerType = <NetworkContainerType>this.migrationStateModel.savedInfo.networkContainerType;
			this.migrationStateModel._databaseBackup.networkShares = this.migrationStateModel.savedInfo.networkShares;
			this.migrationStateModel._databaseBackup.subscription = <Subscription>this.migrationStateModel.savedInfo.targetSubscription;
			this.migrationStateModel._databaseBackup.blobs = this.migrationStateModel.savedInfo.blobs;
			this.migrationStateModel._targetDatabaseNames = this.migrationStateModel.savedInfo.targetDatabaseNames;
		}
		if (this.migrationStateModel.refreshDatabaseBackupPage) {
			try {
				if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
					this.migrationStateModel._migrationDbs = this.migrationStateModel.savedInfo.databaseList;
				}
				const isOfflineMigration = this.migrationStateModel._databaseBackup?.migrationMode === MigrationMode.OFFLINE;
				const lastBackupFileColumnIndex = this._blobContainerTargetDatabaseNamesTable.columns.length - 1;
				this._blobContainerTargetDatabaseNamesTable.columns[lastBackupFileColumnIndex].hidden = !isOfflineMigration;
				this._blobContainerTargetDatabaseNamesTable.columns.forEach(column => {
					column.width = isOfflineMigration ? WIZARD_TABLE_COLUMN_WIDTH_SMALL : WIZARD_TABLE_COLUMN_WIDTH;
				});

				if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
					if (this.migrationStateModel.savedInfo.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
						this._networkShareButton.checked = true;
					} else {
						this._networkShareButton.checked = false;
						this._networkTableContainer.display = 'none';
						await this._networkShareContainer.updateCssStyles({ 'display': 'none' });
					}
				}

				if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
					if (this.migrationStateModel.savedInfo.networkContainerType === NetworkContainerType.BLOB_CONTAINER) {
						this._blobContainerButton.checked = true;
					} else {
						this._blobContainerButton.checked = false;
						this._blobTableContainer.display = 'none';
						await this._blobContainer.updateCssStyles({ 'display': 'none' });
					}
				}

				if (!(this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
					await this._targetDatabaseContainer.updateCssStyles({ 'display': 'none' });
					await this._networkShareStorageAccountDetails.updateCssStyles({ 'display': 'none' });
				}
				const connectionProfile = await this.migrationStateModel.getSourceConnectionProfile();
				const queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>((await this.migrationStateModel.getSourceConnectionProfile()).providerId, azdata.DataProviderType.QueryProvider);
				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._sourceHelpText.value = constants.SQL_SOURCE_DETAILS(this.migrationStateModel._authenticationType, connectionProfile.serverName);
				this._sqlSourceUsernameInput.value = username;
				this._sqlSourcePassword.value = (await azdata.connection.getCredentials(this.migrationStateModel.sourceConnectionId)).password;

				this._networkShareTargetDatabaseNames = [];
				this._networkShareLocations = [];
				this._blobContainerTargetDatabaseNames = [];
				this._blobContainerResourceGroupDropdowns = [];
				this._blobContainerStorageAccountDropdowns = [];
				this._blobContainerDropdowns = [];
				this._blobContainerLastBackupFileDropdowns = [];

				if (this.migrationStateModel._targetType === MigrationTargetType.SQLMI) {
					this._existingDatabases = await this.migrationStateModel.getManagedDatabases();
				}
				this.migrationStateModel._targetDatabaseNames = [];
				this.migrationStateModel._databaseBackup.blobs = [];
				this.migrationStateModel._databaseBackup.networkShares = [];
				this.migrationStateModel._migrationDbs.forEach((db, index) => {
					this.migrationStateModel._targetDatabaseNames.push(db);
					this.migrationStateModel._databaseBackup.blobs.push(<Blob>{});
					this.migrationStateModel._databaseBackup.networkShares.push(<NetworkShare>{});
					const targetDatabaseInput = this._view.modelBuilder.inputBox().withProps({
						required: true,
						value: db,
						width: WIZARD_TABLE_COLUMN_WIDTH
					}).withValidation(c => {
						if (this._networkShareTargetDatabaseNames.filter(t => t.value === c.value).length > 1) { //Making sure no databases have duplicate values.
							c.validationErrorMessage = constants.DUPLICATE_NAME_ERROR;
							return false;
						}
						if (this.migrationStateModel._targetType === MigrationTargetType.SQLMI && this._existingDatabases.includes(c.value!)) { // Making sure if database with same name is not present on the target Azure SQL
							c.validationErrorMessage = constants.DATABASE_ALREADY_EXISTS_MI(c.value!, this.migrationStateModel._targetServerInstance.name);
							return false;
						}
						if (c.value!.length < 1 || c.value!.length > 128 || !/[^<>*%&:\\\/?]/.test(c.value!)) {
							c.validationErrorMessage = constants.INVALID_TARGET_NAME_ERROR;
							return false;
						}
						return true;
					}).component();
					this._disposables.push(targetDatabaseInput.onTextChanged(async (value) => {
						this.migrationStateModel._targetDatabaseNames[index] = value.trim();
						await this.validateFields();
					}));
					if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
						targetDatabaseInput.value = this.migrationStateModel.savedInfo.targetDatabaseNames[index];
					} else {
						targetDatabaseInput.value = this.migrationStateModel._targetDatabaseNames[index];
					}
					this._networkShareTargetDatabaseNames.push(targetDatabaseInput);

					const networkShareLocationInput = this._view.modelBuilder.inputBox().withProps({
						required: true,
						placeHolder: constants.NETWORK_SHARE_PATH_FORMAT,
						validationErrorMessage: constants.INVALID_NETWORK_SHARE_LOCATION,
						width: '300px'
					}).withValidation(c => {
						if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
							if (c.value) {
								if (!/^[\\\/]{2,}[^\\\/]+[\\\/]+[^\\\/]+/.test(c.value)) {
									return false;
								}
							}
						}
						return true;
					}).component();
					this._disposables.push(networkShareLocationInput.onTextChanged(async (value) => {
						this.migrationStateModel._databaseBackup.networkShares[index].networkShareLocation = value.trim();
						await this.validateFields();
					}));
					if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
						networkShareLocationInput.value = this.migrationStateModel.savedInfo.networkShares[index].networkShareLocation;
					} else {
						networkShareLocationInput.value = this.migrationStateModel._databaseBackup.networkShares[index]?.networkShareLocation;
					}
					this._networkShareLocations.push(networkShareLocationInput);

					const blobTargetDatabaseInput = this._view.modelBuilder.inputBox().withProps({
						required: true,
						value: db,
					}).withValidation(c => {
						if (this._blobContainerTargetDatabaseNames.filter(t => t.value === c.value).length > 1) { //Making sure no databases have duplicate values.
							c.validationErrorMessage = constants.DUPLICATE_NAME_ERROR;
							return false;
						}
						if (this.migrationStateModel._targetType === MigrationTargetType.SQLMI && this._existingDatabases.includes(c.value!)) { // Making sure if database with same name is not present on the target Azure SQL
							c.validationErrorMessage = constants.DATABASE_ALREADY_EXISTS_MI(c.value!, this.migrationStateModel._targetServerInstance.name);
							return false;
						}
						if (c.value!.length < 1 || c.value!.length > 128 || !/[^<>*%&:\\\/?]/.test(c.value!)) {
							c.validationErrorMessage = constants.INVALID_TARGET_NAME_ERROR;
							return false;
						}
						return true;
					}).component();
					this._disposables.push(blobTargetDatabaseInput.onTextChanged((value) => {
						this.migrationStateModel._targetDatabaseNames[index] = value.trim();
					}));
					if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) {
						blobTargetDatabaseInput.value = this.migrationStateModel.savedInfo.targetDatabaseNames[index];
					} else {
						targetDatabaseInput.value = this.migrationStateModel._targetDatabaseNames[index];
					}
					this._blobContainerTargetDatabaseNames.push(blobTargetDatabaseInput);

					const blobContainerResourceDropdown = this._view.modelBuilder.dropDown().withProps({
						ariaLabel: constants.BLOB_CONTAINER_RESOURCE_GROUP,
						editable: true,
						fireOnTextChange: true,
						required: true,
					}).component();

					const blobContainerStorageAccountDropdown = this._view.modelBuilder.dropDown().withProps({
						ariaLabel: constants.BLOB_CONTAINER_STORAGE_ACCOUNT,
						editable: true,
						fireOnTextChange: true,
						required: true,
						enabled: false,
					}).component();

					const blobContainerDropdown = this._view.modelBuilder.dropDown().withProps({
						ariaLabel: constants.BLOB_CONTAINER,
						editable: true,
						fireOnTextChange: true,
						required: true,
						enabled: false,
					}).component();

					const blobContainerLastBackupFileDropdown = this._view.modelBuilder.dropDown().withProps({
						ariaLabel: constants.BLOB_CONTAINER_LAST_BACKUP_FILE,
						editable: true,
						fireOnTextChange: true,
						required: true,
						enabled: false,
					}).component();

					this._disposables.push(blobContainerResourceDropdown.onValueChanged(async (value) => {
						const selectedIndex = findDropDownItemIndex(blobContainerResourceDropdown, value);
						if (selectedIndex > -1 && !blobResourceGroupErrorStrings.includes(value)) {
							this.migrationStateModel._databaseBackup.blobs[index].resourceGroup = this.migrationStateModel.getAzureResourceGroup(selectedIndex);
							await this.loadBlobStorageDropdown(index);
							await blobContainerStorageAccountDropdown.updateProperties({ enabled: true });
						} else {
							await this.disableBlobTableDropdowns(index, constants.RESOURCE_GROUP);
						}
					}));
					this._blobContainerResourceGroupDropdowns.push(blobContainerResourceDropdown);

					this._disposables.push(blobContainerStorageAccountDropdown.onValueChanged(async (value) => {
						const selectedIndex = findDropDownItemIndex(blobContainerStorageAccountDropdown, value);
						if (selectedIndex > -1 && !blobStorageAccountErrorStrings.includes(value)) {
							this.migrationStateModel._databaseBackup.blobs[index].storageAccount = this.migrationStateModel.getStorageAccount(selectedIndex);
							await this.loadBlobContainerDropdown(index);
							await blobContainerDropdown.updateProperties({ enabled: true });
						} else {
							await this.disableBlobTableDropdowns(index, constants.STORAGE_ACCOUNT);
						}
					}));
					this._blobContainerStorageAccountDropdowns.push(blobContainerStorageAccountDropdown);

					this._disposables.push(blobContainerDropdown.onValueChanged(async (value) => {
						const selectedIndex = findDropDownItemIndex(blobContainerDropdown, value);
						if (selectedIndex > -1 && !blobContainerErrorStrings.includes(value)) {
							this.migrationStateModel._databaseBackup.blobs[index].blobContainer = this.migrationStateModel.getBlobContainer(selectedIndex);
							if (this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE) {
								await this.loadBlobLastBackupFileDropdown(index);
								await blobContainerLastBackupFileDropdown.updateProperties({ enabled: true });
							}
						} else {
							await this.disableBlobTableDropdowns(index, constants.BLOB_CONTAINER);
						}
					}));
					this._blobContainerDropdowns.push(blobContainerDropdown);

					if (this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE) {
						this._disposables.push(blobContainerLastBackupFileDropdown.onValueChanged(value => {
							const selectedIndex = findDropDownItemIndex(blobContainerLastBackupFileDropdown, value);
							if (selectedIndex > -1 && !blobFileErrorStrings.includes(value)) {
								this.migrationStateModel._databaseBackup.blobs[index].lastBackupFile = this.migrationStateModel.getBlobLastBackupFileName(selectedIndex);
							}
						}));
						this._blobContainerLastBackupFileDropdowns.push(blobContainerLastBackupFileDropdown);
					}
				});


				let data: azdata.DeclarativeTableCellValue[][] = [];
				this.migrationStateModel._migrationDbs.forEach((db, index) => {
					const targetRow: azdata.DeclarativeTableCellValue[] = [];
					targetRow.push({
						value: db
					});
					targetRow.push({
						value: this._networkShareTargetDatabaseNames[index]
					});
					targetRow.push({
						value: this._networkShareLocations[index]
					});
					data.push(targetRow);
				});
				await this._networkShareTargetDatabaseNamesTable.setDataValues(data);

				data = [];
				this.migrationStateModel._migrationDbs.forEach((db, index) => {
					const targetRow: azdata.DeclarativeTableCellValue[] = [];
					targetRow.push({
						value: db
					});
					targetRow.push({
						value: this._blobContainerTargetDatabaseNames[index]
					});
					targetRow.push({
						value: this._blobContainerResourceGroupDropdowns[index]
					});
					targetRow.push({
						value: this._blobContainerStorageAccountDropdowns[index]
					});
					targetRow.push({
						value: this._blobContainerDropdowns[index]
					});
					targetRow.push({
						value: this._blobContainerLastBackupFileDropdowns[index]
					});
					data.push(targetRow);
				});
				await this._blobContainerTargetDatabaseNamesTable.setDataValues(data);

				await this.getSubscriptionValues();
				this.migrationStateModel.refreshDatabaseBackupPage = false;
			} catch (error) {
				console.log(error);
				let errorText = error?.message;
				if (errorText === constants.INVALID_OWNER_URI) {
					errorText = constants.DATABASE_BACKUP_PAGE_LOAD_ERROR;
				}
				this.wizard.message = {
					text: errorText,
					description: error?.stack,
					level: azdata.window.MessageLevel.Error
				};
			}
		}

		this.wizard.registerNavigationValidator((pageChangeInfo) => {
			if (pageChangeInfo.newPage < pageChangeInfo.lastPage) {
				return true;
			}

			const errors: string[] = [];

			switch (this.migrationStateModel._databaseBackup.networkContainerType) {
				case NetworkContainerType.NETWORK_SHARE:
					if ((<azdata.CategoryValue>this._networkShareStorageAccountResourceGroupDropdown.value)?.displayName === constants.RESOURCE_GROUP_NOT_FOUND) {
						errors.push(constants.INVALID_RESOURCE_GROUP_ERROR);
					}
					if ((<azdata.CategoryValue>this._networkShareContainerStorageAccountDropdown.value)?.displayName === constants.NO_STORAGE_ACCOUNT_FOUND) {
						errors.push(constants.INVALID_STORAGE_ACCOUNT_ERROR);
					}
					break;
				case NetworkContainerType.BLOB_CONTAINER:
					this._blobContainerResourceGroupDropdowns.forEach((v, index) => {
						if (this.shouldDisplayBlobDropdownError(v, [constants.RESOURCE_GROUP_NOT_FOUND])) {
							errors.push(constants.INVALID_BLOB_RESOURCE_GROUP_ERROR(this.migrationStateModel._migrationDbs[index]));
						}
					});
					this._blobContainerStorageAccountDropdowns.forEach((v, index) => {
						if (this.shouldDisplayBlobDropdownError(v, [constants.NO_STORAGE_ACCOUNT_FOUND, constants.SELECT_RESOURCE_GROUP_PROMPT])) {
							errors.push(constants.INVALID_BLOB_STORAGE_ACCOUNT_ERROR(this.migrationStateModel._migrationDbs[index]));
						}
					});
					this._blobContainerDropdowns.forEach((v, index) => {
						if (this.shouldDisplayBlobDropdownError(v, [constants.NO_BLOBCONTAINERS_FOUND, constants.SELECT_STORAGE_ACCOUNT])) {
							errors.push(constants.INVALID_BLOB_CONTAINER_ERROR(this.migrationStateModel._migrationDbs[index]));
						}
					});

					if (this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE) {
						this._blobContainerLastBackupFileDropdowns.forEach((v, index) => {
							if (this.shouldDisplayBlobDropdownError(v, [constants.NO_BLOBFILES_FOUND, constants.SELECT_BLOB_CONTAINER])) {
								errors.push(constants.INVALID_BLOB_LAST_BACKUP_FILE_ERROR(this.migrationStateModel._migrationDbs[index]));
							}
						});
					}

					if (errors.length > 0) {
						const duplicates: Map<string, number[]> = new Map();
						for (let i = 0; i < this.migrationStateModel._targetDatabaseNames.length; i++) {
							const blobContainerId = this.migrationStateModel._databaseBackup.blobs[i].blobContainer?.id;
							if (duplicates.has(blobContainerId)) {
								duplicates.get(blobContainerId)?.push(i);
							} else {
								duplicates.set(blobContainerId, [i]);
							}
						}
						duplicates.forEach((d) => {
							if (d.length > 1) {
								const dupString = `${d.map(index => this.migrationStateModel._migrationDbs[index]).join(', ')}`;
								errors.push(constants.PROVIDE_UNIQUE_CONTAINERS + dupString);
							}
						});
					}

					break;
			}

			this.migrationStateModel._targetDatabaseNames.forEach(t => {
				if (this.migrationStateModel._targetType === MigrationTargetType.SQLMI && this._existingDatabases.includes(t)) { // Making sure if database with same name is not present on the target Azure SQL
					errors.push(constants.DATABASE_ALREADY_EXISTS_MI(t, this.migrationStateModel._targetServerInstance.name));
				}
			});

			this.wizard.message = {
				text: errors.join(EOL),
				level: azdata.window.MessageLevel.Error
			};
			if (errors.length > 0) {
				return false;
			}
			return true;
		});
	}