diff --git a/extensions/sql-migration/src/constants/strings.ts b/extensions/sql-migration/src/constants/strings.ts index 49f5a1a087..2974caf824 100644 --- a/extensions/sql-migration/src/constants/strings.ts +++ b/extensions/sql-migration/src/constants/strings.ts @@ -79,6 +79,7 @@ export const DATABASE_BACKUP_NC_NETWORK_SHARE_RADIO_LABEL = localize('sql.migrat export const DATABASE_BACKUP_NC_BLOB_STORAGE_RADIO_LABEL = localize('sql.migration.nc.blob.storage.radio.label', "My database backups are in an Azure Storage Blob Container"); export const DATABASE_BACKUP_NETWORK_SHARE_HEADER_TEXT = localize('sql.migration.network.share.header.text', "Network share details"); export const DATABASE_BACKUP_NC_NETWORK_SHARE_HELP_TEXT = localize('sql.migration.network.share.help.text', "Provide the network share location that contains backups and the user credentials that has read access to the share"); +export const DATABASE_BACKUP_NETWORK_SHARE_TABLE_HELP_TEXT = localize('sql.migration.network.share.storage.table.help', "Enter target database name for the selected source database(s)."); export const DATABASE_BACKUP_NETWORK_SHARE_LOCATION_LABEL = localize('sql.migration.network.share.location.label', "Network share location that contains backups."); export const DATABASE_SERVICE_ACCOUNT_INFO_TEXT = localize('sql.migration.service.account.info.text', "Ensure that the service account running the source SQL Server instance has read privileges on the network share."); export const DATABASE_BACKUP_NETWORK_SHARE_WINDOWS_USER_LABEL = localize('sql.migration.network.share.windows.user.label', "Windows user account with read access to the network share location."); @@ -90,6 +91,9 @@ export const DUPLICATE_NAME_ERROR = localize('sql.migration.unique.name', "Selec export function DATABASE_ALREADY_EXISTS_MI(dbName: string, targetName: string): string { return localize('sql.migration.database.already.exists', "Database '{0}' already exists on the target managed instance '{1}'.", dbName, targetName); } +export const DATABASE_BACKUP_BLOB_STORAGE_HEADER_TEXT = localize('sql.migration.blob.storage.header.text', "Azure Storage Blob Container details"); +export const DATABASE_BACKUP_BLOB_STORAGE_HELP_TEXT = localize('sql.migration.blob.storage.help.text', "Provide the Azure Storage Blob Container that contains the backups."); +export const DATABASE_BACKUP_BLOB_STORAGE_TABLE_HELP_TEXT = localize('sql.migration.blob.storage.table.help', "Enter target database name and select resource group, storage account and container for the selected source database(s)."); export const DATABASE_BACKUP_BLOB_STORAGE_SUBSCRIPTION_LABEL = localize('sql.migration.blob.storage.subscription.label', "Select the subscription that contains the storage account."); export const DATABASE_BACKUP_MIGRATION_MODE_LABEL = localize('sql.migration.database.migration.mode.label', "Migration mode"); export const DATABASE_BACKUP_MIGRATION_MODE_DESCRIPTION = localize('sql.migration.database.migration.mode.description', "To migrate to the Azure SQL target, choose a migration mode based on your downtime requirements."); @@ -479,4 +483,3 @@ export function WARNINGS_COUNT(totalCount: number): string { export const AUTHENTICATION_TYPE = localize('sql.migration.authentication.type', "Authentication Type"); export const REFRESH_BUTTON_LABEL = localize('sql.migration.status.refresh.label', 'Refresh'); - diff --git a/extensions/sql-migration/src/wizard/databaseBackupPage.ts b/extensions/sql-migration/src/wizard/databaseBackupPage.ts index 6e7d959226..ca8f1e519b 100644 --- a/extensions/sql-migration/src/wizard/databaseBackupPage.ts +++ b/extensions/sql-migration/src/wizard/databaseBackupPage.ts @@ -14,7 +14,8 @@ import { IconPathHelper } from '../constants/iconPathHelper'; import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController'; import { findDropDownItemIndex, selectDropDownIndex } from '../api/utils'; -const WIZARD_TABLE_COLUMN_WIDTH = '150px'; +const WIZARD_TABLE_COLUMN_WIDTH = '200px'; +const WIZARD_TABLE_COLUMN_WIDTH_SMALL = '170px'; const blobResourceGroupErrorStrings = [constants.RESOURCE_GROUP_NOT_FOUND]; const blobStorageAccountErrorStrings = [constants.NO_STORAGE_ACCOUNT_FOUND, constants.SELECT_RESOURCE_GROUP]; @@ -366,6 +367,22 @@ export class DatabaseBackupPage extends MigrationWizardPage { } private createBlobContainer(): azdata.FlexContainer { + const blobHeading = this._view.modelBuilder.text().withProps({ + value: constants.DATABASE_BACKUP_BLOB_STORAGE_HEADER_TEXT, + width: WIZARD_INPUT_COMPONENT_WIDTH, + CSSStyles: { + 'font-size': '14px', + 'font-weight': 'bold' + } + }).component(); + + const blobHelpText = this._view.modelBuilder.text().withProps({ + value: constants.DATABASE_BACKUP_BLOB_STORAGE_HELP_TEXT, + width: WIZARD_INPUT_COMPONENT_WIDTH, + CSSStyles: { + 'font-size': '13px', + } + }).component(); const subscriptionLabel = this._view.modelBuilder.text() .withProps({ @@ -396,6 +413,8 @@ export class DatabaseBackupPage extends MigrationWizardPage { const flexContainer = this._view.modelBuilder.flexContainer() .withItems( [ + blobHeading, + blobHelpText, subscriptionLabel, this._blobContainerSubscription, locationLabel, @@ -425,6 +444,24 @@ export class DatabaseBackupPage extends MigrationWizardPage { 'border-bottom': '1px solid', }; + const networkShareTableText = this._view.modelBuilder.text() + .withProps({ + value: constants.DATABASE_BACKUP_NETWORK_SHARE_TABLE_HELP_TEXT, + CSSStyles: { + 'font-size': '13px', + 'font-weight': 'bold' + } + }).component(); + + const blobTableText = this._view.modelBuilder.text() + .withProps({ + value: constants.DATABASE_BACKUP_BLOB_STORAGE_TABLE_HELP_TEXT, + CSSStyles: { + 'font-size': '13px', + 'font-weight': 'bold' + } + }).component(); + this._newtworkShareTargetDatabaseNamesTable = this._view.modelBuilder.declarativeTable().withProps({ columns: [ { @@ -445,6 +482,7 @@ export class DatabaseBackupPage extends MigrationWizardPage { } ] }).component(); + this._blobContainerTargetDatabaseNamesTable = this._view.modelBuilder.declarativeTable().withProps({ columns: [ { @@ -494,11 +532,13 @@ export class DatabaseBackupPage extends MigrationWizardPage { headerCssStyles: headerCssStyles, isReadOnly: true, width: WIZARD_TABLE_COLUMN_WIDTH, + hidden: true } ] }).component(); this._networkTableContainer = this._view.modelBuilder.flexContainer().withItems([ + networkShareTableText, this._newtworkShareTargetDatabaseNamesTable ]).component(); @@ -511,6 +551,7 @@ export class DatabaseBackupPage extends MigrationWizardPage { }).component(); this._blobTableContainer = this._view.modelBuilder.flexContainer().withItems([ + blobTableText, allFieldsRequiredLabel, this._blobContainerTargetDatabaseNamesTable ]).component(); @@ -682,6 +723,9 @@ export class DatabaseBackupPage extends MigrationWizardPage { 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; + }); this._networkShareButton.checked = false; this._networkTableContainer.display = 'none'; @@ -745,7 +789,6 @@ export class DatabaseBackupPage extends MigrationWizardPage { const blobtargetDatabaseInput = this._view.modelBuilder.inputBox().withProps({ required: true, value: db, - width: WIZARD_TABLE_COLUMN_WIDTH }).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; @@ -768,7 +811,6 @@ export class DatabaseBackupPage extends MigrationWizardPage { const blobContainerResourceDropdown = this._view.modelBuilder.dropDown().withProps({ ariaLabel: constants.BLOB_CONTAINER_RESOURCE_GROUP, - width: WIZARD_TABLE_COLUMN_WIDTH, editable: true, fireOnTextChange: true, required: true, @@ -776,7 +818,6 @@ export class DatabaseBackupPage extends MigrationWizardPage { const blobContainerStorageAccountDropdown = this._view.modelBuilder.dropDown().withProps({ ariaLabel: constants.BLOB_CONTAINER_STORAGE_ACCOUNT, - width: WIZARD_TABLE_COLUMN_WIDTH, editable: true, fireOnTextChange: true, required: true, @@ -785,7 +826,6 @@ export class DatabaseBackupPage extends MigrationWizardPage { const blobContainerDropdown = this._view.modelBuilder.dropDown().withProps({ ariaLabel: constants.BLOB_CONTAINER, - width: WIZARD_TABLE_COLUMN_WIDTH, editable: true, fireOnTextChange: true, required: true, @@ -794,7 +834,6 @@ export class DatabaseBackupPage extends MigrationWizardPage { const blobContainerLastBackupFileDropdown = this._view.modelBuilder.dropDown().withProps({ ariaLabel: constants.BLOB_CONTAINER_LAST_BACKUP_FILE, - width: WIZARD_TABLE_COLUMN_WIDTH, editable: true, fireOnTextChange: true, required: true,