mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
[SQL Migration] Allow folders inside blob containers (#21952)
* WIP * WIP * WIP - add new property to blob * Add error messages * Fix undefined for offline scenario * Add support for offline scenario * Clean up * vbump extension * remove >1 level deep folders * fix [object] object issue * Remove unnecessary asyncs * don't allow >1 level deep for offline scenario lastBackupFile
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
"name": "sql-migration",
|
"name": "sql-migration",
|
||||||
"displayName": "%displayName%",
|
"displayName": "%displayName%",
|
||||||
"description": "%description%",
|
"description": "%description%",
|
||||||
"version": "1.4.0",
|
"version": "1.4.1",
|
||||||
"publisher": "Microsoft",
|
"publisher": "Microsoft",
|
||||||
"preview": false,
|
"preview": false,
|
||||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",
|
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/main/LICENSE.txt",
|
||||||
|
|||||||
@@ -705,6 +705,15 @@ export async function getAzureSqlMigrationServices(account?: Account, subscripti
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Blob {
|
||||||
|
resourceGroup: azureResource.AzureResourceResourceGroup;
|
||||||
|
storageAccount: azureResource.AzureGraphResource;
|
||||||
|
blobContainer: azureResource.BlobContainer;
|
||||||
|
storageKey: string;
|
||||||
|
lastBackupFile?: string;
|
||||||
|
folderName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getBlobContainer(account?: Account, subscription?: azureResource.AzureResourceSubscription, storageAccount?: azure.StorageAccount): Promise<azureResource.BlobContainer[]> {
|
export async function getBlobContainer(account?: Account, subscription?: azureResource.AzureResourceSubscription, storageAccount?: azure.StorageAccount): Promise<azureResource.BlobContainer[]> {
|
||||||
let blobContainers: azureResource.BlobContainer[] = [];
|
let blobContainers: azureResource.BlobContainer[] = [];
|
||||||
try {
|
try {
|
||||||
@@ -722,7 +731,14 @@ export async function getBlobLastBackupFileNames(account?: Account, subscription
|
|||||||
let lastFileNames: azureResource.Blob[] = [];
|
let lastFileNames: azureResource.Blob[] = [];
|
||||||
try {
|
try {
|
||||||
if (account && subscription && storageAccount && blobContainer) {
|
if (account && subscription && storageAccount && blobContainer) {
|
||||||
lastFileNames = await azure.getBlobs(account, subscription, storageAccount, blobContainer.name);
|
const blobs = await azure.getBlobs(account, subscription, storageAccount, blobContainer.name);
|
||||||
|
|
||||||
|
blobs.forEach(blob => {
|
||||||
|
// only show at most one folder deep
|
||||||
|
if ((blob.name.split('/').length === 1 || blob.name.split('/').length === 2) && !lastFileNames.includes(blob)) {
|
||||||
|
lastFileNames.push(blob);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(TelemetryViews.Utils, 'utils.getBlobLastBackupFileNames', e);
|
logError(TelemetryViews.Utils, 'utils.getBlobLastBackupFileNames', e);
|
||||||
@@ -731,6 +747,64 @@ export async function getBlobLastBackupFileNames(account?: Account, subscription
|
|||||||
return lastFileNames;
|
return lastFileNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getBlobFolders(account?: Account, subscription?: azureResource.AzureResourceSubscription, storageAccount?: azure.StorageAccount, blobContainer?: azureResource.BlobContainer): Promise<string[]> {
|
||||||
|
let folders: string[] = [];
|
||||||
|
try {
|
||||||
|
if (account && subscription && storageAccount && blobContainer) {
|
||||||
|
const blobs = await azure.getBlobs(account, subscription, storageAccount, blobContainer.name);
|
||||||
|
|
||||||
|
blobs.forEach(blob => {
|
||||||
|
let folder: string = '';
|
||||||
|
|
||||||
|
if (blob.name.split('/').length === 1) {
|
||||||
|
folder = '/'; // no folder (root)
|
||||||
|
} else if (blob.name.split('/').length === 2) {
|
||||||
|
folder = blob.name.split('/')[0]; // one folder deep
|
||||||
|
}
|
||||||
|
|
||||||
|
if (folder && !folders.includes(folder)) {
|
||||||
|
folders.push(folder);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logError(TelemetryViews.Utils, 'utils.getBlobLastBackupFolders', e);
|
||||||
|
}
|
||||||
|
folders.sort();
|
||||||
|
return folders;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBlobContainerNameWithFolder(blob: Blob, isOfflineMigration: boolean): string {
|
||||||
|
const blobContainerName = blob.blobContainer.name;
|
||||||
|
|
||||||
|
if (isOfflineMigration) {
|
||||||
|
const lastBackupFile = blob.lastBackupFile;
|
||||||
|
if (!lastBackupFile || lastBackupFile.split('/').length !== 2) {
|
||||||
|
return blobContainerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for offline scenario, take the folder name out of the blob name and add it to the container name instead
|
||||||
|
return blobContainerName + '/' + lastBackupFile.split('/')[0];
|
||||||
|
} else {
|
||||||
|
const folderName = blob.folderName;
|
||||||
|
if (!folderName || folderName === '/' || folderName === 'undefined') {
|
||||||
|
return blobContainerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for online scenario, take the explicitly provided folder name
|
||||||
|
return blobContainerName + '/' + folderName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLastBackupFileNameWithoutFolder(blob: Blob) {
|
||||||
|
const lastBackupFile = blob.lastBackupFile;
|
||||||
|
if (!lastBackupFile || lastBackupFile.split('/').length !== 2) {
|
||||||
|
return lastBackupFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastBackupFile.split('/')[1];
|
||||||
|
}
|
||||||
|
|
||||||
export function getAzureResourceDropdownValues(
|
export function getAzureResourceDropdownValues(
|
||||||
azureResources: { location: string, id: string, name: string }[],
|
azureResources: { location: string, id: string, name: string }[],
|
||||||
location: azureResource.AzureLocation | undefined,
|
location: azureResource.AzureLocation | undefined,
|
||||||
@@ -762,12 +836,16 @@ export function getResourceDropdownValues(resources: { id: string, name: string
|
|||||||
|| [{ name: '', displayName: resourceNotFoundMessage }];
|
|| [{ name: '', displayName: resourceNotFoundMessage }];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAzureTenantsDropdownValues(tenants: Tenant[]): Promise<CategoryValue[]> {
|
export function getAzureTenantsDropdownValues(tenants: Tenant[]): CategoryValue[] {
|
||||||
|
if (!tenants || !tenants.length) {
|
||||||
|
return [{ name: '', displayName: constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR }];
|
||||||
|
}
|
||||||
|
|
||||||
return tenants?.map(tenant => { return { name: tenant.id, displayName: tenant.displayName }; })
|
return tenants?.map(tenant => { return { name: tenant.id, displayName: tenant.displayName }; })
|
||||||
|| [{ name: '', displayName: constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR }];
|
|| [{ name: '', displayName: constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR }];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAzureLocationsDropdownValues(locations: azureResource.AzureLocation[]): Promise<CategoryValue[]> {
|
export function getAzureLocationsDropdownValues(locations: azureResource.AzureLocation[]): CategoryValue[] {
|
||||||
if (!locations || !locations.length) {
|
if (!locations || !locations.length) {
|
||||||
return [{ name: '', displayName: constants.NO_LOCATION_FOUND }];
|
return [{ name: '', displayName: constants.NO_LOCATION_FOUND }];
|
||||||
}
|
}
|
||||||
@@ -776,11 +854,24 @@ export async function getAzureLocationsDropdownValues(locations: azureResource.A
|
|||||||
|| [{ name: '', displayName: constants.NO_LOCATION_FOUND }];
|
|| [{ name: '', displayName: constants.NO_LOCATION_FOUND }];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getBlobLastBackupFileNamesValues(blobs: azureResource.Blob[]): Promise<CategoryValue[]> {
|
export function getBlobLastBackupFileNamesValues(blobs: azureResource.Blob[]): CategoryValue[] {
|
||||||
|
if (!blobs || !blobs.length) {
|
||||||
|
return [{ name: '', displayName: constants.NO_BLOBFILES_FOUND }];
|
||||||
|
}
|
||||||
|
|
||||||
return blobs?.map(blob => { return { name: blob.name, displayName: blob.name }; })
|
return blobs?.map(blob => { return { name: blob.name, displayName: blob.name }; })
|
||||||
|| [{ name: '', displayName: constants.NO_BLOBFILES_FOUND }];
|
|| [{ name: '', displayName: constants.NO_BLOBFILES_FOUND }];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getBlobFolderValues(folders: string[]): CategoryValue[] {
|
||||||
|
if (!folders || !folders.length) {
|
||||||
|
return [{ name: '', displayName: constants.NO_BLOBFOLDERS_FOUND }];
|
||||||
|
}
|
||||||
|
|
||||||
|
return folders?.map(folder => { return { name: folder, displayName: folder }; })
|
||||||
|
|| [{ name: '', displayName: constants.NO_BLOBFOLDERS_FOUND }];
|
||||||
|
}
|
||||||
|
|
||||||
export async function updateControlDisplay(control: Component, visible: boolean, displayStyle: DisplayType = 'inline'): Promise<void> {
|
export async function updateControlDisplay(control: Component, visible: boolean, displayStyle: DisplayType = 'inline'): Promise<void> {
|
||||||
const display = visible ? displayStyle : 'none';
|
const display = visible ? displayStyle : 'none';
|
||||||
control.display = display;
|
control.display = display;
|
||||||
|
|||||||
@@ -603,6 +603,7 @@ export const NO_STORAGE_ACCOUNT_FOUND = localize('sql.migration.no.storageAccoun
|
|||||||
export const NO_FILESHARES_FOUND = localize('sql.migration.no.fileShares.found', "No file shares found.");
|
export const NO_FILESHARES_FOUND = localize('sql.migration.no.fileShares.found', "No file shares found.");
|
||||||
export const NO_BLOBCONTAINERS_FOUND = localize('sql.migration.no.blobContainers.found', "No blob containers found.");
|
export const NO_BLOBCONTAINERS_FOUND = localize('sql.migration.no.blobContainers.found', "No blob containers found.");
|
||||||
export const NO_BLOBFILES_FOUND = localize('sql.migration.no.blobFiles.found', "No blob files found.");
|
export const NO_BLOBFILES_FOUND = localize('sql.migration.no.blobFiles.found', "No blob files found.");
|
||||||
|
export const NO_BLOBFOLDERS_FOUND = localize('sql.migration.no.blobFolders.found', "No blob folders found.");
|
||||||
export const INVALID_SUBSCRIPTION_ERROR = localize('sql.migration.invalid.subscription.error', "To continue, select a valid subscription.");
|
export const INVALID_SUBSCRIPTION_ERROR = localize('sql.migration.invalid.subscription.error', "To continue, select a valid subscription.");
|
||||||
export const INVALID_LOCATION_ERROR = localize('sql.migration.invalid.location.error', "To continue, select a valid location.");
|
export const INVALID_LOCATION_ERROR = localize('sql.migration.invalid.location.error', "To continue, select a valid location.");
|
||||||
export const INVALID_RESOURCE_GROUP_ERROR = localize('sql.migration.invalid.resourceGroup.error', "To continue, select a valid resource group.");
|
export const INVALID_RESOURCE_GROUP_ERROR = localize('sql.migration.invalid.resourceGroup.error', "To continue, select a valid resource group.");
|
||||||
@@ -635,6 +636,9 @@ export function INVALID_BLOB_CONTAINER_ERROR(sourceDb: string): string {
|
|||||||
export function INVALID_BLOB_LAST_BACKUP_FILE_ERROR(sourceDb: string): string {
|
export function INVALID_BLOB_LAST_BACKUP_FILE_ERROR(sourceDb: string): string {
|
||||||
return localize('sql.migration.invalid.blob.lastBackupFile.error', "To continue, select a valid last backup file for source database '{0}'.", sourceDb);
|
return localize('sql.migration.invalid.blob.lastBackupFile.error', "To continue, select a valid last backup file for source database '{0}'.", sourceDb);
|
||||||
}
|
}
|
||||||
|
export function INVALID_BLOB_LAST_BACKUP_FOLDER_ERROR(sourceDb: string): string {
|
||||||
|
return localize('sql.migration.invalid.blob.lastBackupFolder.error', "To continue, select a valid backup folder for source database '{0}'.", sourceDb);
|
||||||
|
}
|
||||||
export function INVALID_NON_PAGE_BLOB_BACKUP_FILE_ERROR(sourceDb: string): string {
|
export function INVALID_NON_PAGE_BLOB_BACKUP_FILE_ERROR(sourceDb: string): string {
|
||||||
return localize('sql.migration.invalid.non.page.blob.backupFile.error', "To continue, select a blob container where all the backup files are page blobs for source database '{0}', as block blobs are supported only for targets running SQL Server 2016 or later. Learn more: https://aka.ms/dms-migrations-troubleshooting", sourceDb);
|
return localize('sql.migration.invalid.non.page.blob.backupFile.error', "To continue, select a blob container where all the backup files are page blobs for source database '{0}', as block blobs are supported only for targets running SQL Server 2016 or later. Learn more: https://aka.ms/dms-migrations-troubleshooting", sourceDb);
|
||||||
}
|
}
|
||||||
@@ -907,6 +911,7 @@ export const NETWORK_SHARE = localize('sql.migration.network.share', "Network sh
|
|||||||
export const NETWORK_SHARE_PATH = localize('sql.migration.network.share.path', "Network share path");
|
export const NETWORK_SHARE_PATH = localize('sql.migration.network.share.path', "Network share path");
|
||||||
export const BLOB_CONTAINER = localize('sql.migration.blob.container.title', "Blob container");
|
export const BLOB_CONTAINER = localize('sql.migration.blob.container.title', "Blob container");
|
||||||
export const BLOB_CONTAINER_LAST_BACKUP_FILE = localize('sql.migration.blob.container.last.backup.file.label', "Last backup file");
|
export const BLOB_CONTAINER_LAST_BACKUP_FILE = localize('sql.migration.blob.container.last.backup.file.label', "Last backup file");
|
||||||
|
export const BLOB_CONTAINER_FOLDER = localize('sql.migration.blob.container.folder.label', "Folder");
|
||||||
export const BLOB_CONTAINER_RESOURCE_GROUP = localize('sql.migration.blob.container.label', "Blob container resource group");
|
export const BLOB_CONTAINER_RESOURCE_GROUP = localize('sql.migration.blob.container.label', "Blob container resource group");
|
||||||
export const BLOB_CONTAINER_STORAGE_ACCOUNT = localize('sql.migration.blob.container.storage.account.label', "Blob container storage account");
|
export const BLOB_CONTAINER_STORAGE_ACCOUNT = localize('sql.migration.blob.container.storage.account.label', "Blob container storage account");
|
||||||
export const SOURCE_DATABASES = localize('sql.migration.source.databases', "Source databases");
|
export const SOURCE_DATABASES = localize('sql.migration.source.databases', "Source databases");
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ export class SelectMigrationServiceDialog {
|
|||||||
try {
|
try {
|
||||||
this._accountTenantDropdown.loading = true;
|
this._accountTenantDropdown.loading = true;
|
||||||
this._accountTenants = utils.getAzureTenants(this._serviceContext.azureAccount);
|
this._accountTenants = utils.getAzureTenants(this._serviceContext.azureAccount);
|
||||||
this._accountTenantDropdown.values = await utils.getAzureTenantsDropdownValues(this._accountTenants);
|
this._accountTenantDropdown.values = utils.getAzureTenantsDropdownValues(this._accountTenants);
|
||||||
await this._accountTenantFlexContainer.updateCssStyles(
|
await this._accountTenantFlexContainer.updateCssStyles(
|
||||||
this._accountTenants.length > 1
|
this._accountTenants.length > 1
|
||||||
? STYLE_ShOW
|
? STYLE_ShOW
|
||||||
@@ -426,7 +426,7 @@ export class SelectMigrationServiceDialog {
|
|||||||
this._serviceContext.subscription,
|
this._serviceContext.subscription,
|
||||||
this._sqlMigrationServices);
|
this._sqlMigrationServices);
|
||||||
|
|
||||||
this._azureLocationDropdown.values = await utils.getAzureLocationsDropdownValues(this._locations);
|
this._azureLocationDropdown.values = utils.getAzureLocationsDropdownValues(this._locations);
|
||||||
if (this._azureLocationDropdown.values.length > 0) {
|
if (this._azureLocationDropdown.values.length > 0) {
|
||||||
utils.selectDefaultDropdownValue(
|
utils.selectDefaultDropdownValue(
|
||||||
this._azureLocationDropdown,
|
this._azureLocationDropdown,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import * as constants from '../constants/strings';
|
|||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews, logError } from '../telemetry';
|
import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews, logError } from '../telemetry';
|
||||||
import { hashString, deepClone } from '../api/utils';
|
import { hashString, deepClone, getBlobContainerNameWithFolder, Blob, getLastBackupFileNameWithoutFolder } from '../api/utils';
|
||||||
import { SKURecommendationPage } from '../wizard/skuRecommendationPage';
|
import { SKURecommendationPage } from '../wizard/skuRecommendationPage';
|
||||||
import { excludeDatabases, getEncryptConnectionValue, getSourceConnectionId, getSourceConnectionProfile, getSourceConnectionServerInfo, getSourceConnectionString, getSourceConnectionUri, getTrustServerCertificateValue, SourceDatabaseInfo, TargetDatabaseInfo } from '../api/sqlUtils';
|
import { excludeDatabases, getEncryptConnectionValue, getSourceConnectionId, getSourceConnectionProfile, getSourceConnectionServerInfo, getSourceConnectionString, getSourceConnectionUri, getTrustServerCertificateValue, SourceDatabaseInfo, TargetDatabaseInfo } from '../api/sqlUtils';
|
||||||
import { LoginMigrationModel } from './loginMigrationModel';
|
import { LoginMigrationModel } from './loginMigrationModel';
|
||||||
@@ -126,14 +126,6 @@ export interface NetworkShare {
|
|||||||
storageKey: string;
|
storageKey: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Blob {
|
|
||||||
resourceGroup: azurecore.azureResource.AzureResourceResourceGroup;
|
|
||||||
storageAccount: StorageAccount;
|
|
||||||
blobContainer: azurecore.azureResource.BlobContainer;
|
|
||||||
storageKey: string;
|
|
||||||
lastBackupFile?: string; // _todo: does it make sense to store the last backup file here?
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Model {
|
export interface Model {
|
||||||
readonly currentState: State;
|
readonly currentState: State;
|
||||||
gatheringInformationError: string | undefined;
|
gatheringInformationError: string | undefined;
|
||||||
@@ -206,6 +198,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
|||||||
public _fileShares!: azurecore.azureResource.FileShare[];
|
public _fileShares!: azurecore.azureResource.FileShare[];
|
||||||
public _blobContainers!: azurecore.azureResource.BlobContainer[];
|
public _blobContainers!: azurecore.azureResource.BlobContainer[];
|
||||||
public _lastFileNames!: azurecore.azureResource.Blob[];
|
public _lastFileNames!: azurecore.azureResource.Blob[];
|
||||||
|
public _blobContainerFolders!: string[];
|
||||||
public _sourceDatabaseNames!: string[];
|
public _sourceDatabaseNames!: string[];
|
||||||
public _targetDatabaseNames!: string[];
|
public _targetDatabaseNames!: string[];
|
||||||
|
|
||||||
@@ -1086,7 +1079,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
|||||||
azureBlob: {
|
azureBlob: {
|
||||||
storageAccountResourceId: this._databaseBackup.blobs[i].storageAccount.id,
|
storageAccountResourceId: this._databaseBackup.blobs[i].storageAccount.id,
|
||||||
accountKey: this._databaseBackup.blobs[i].storageKey,
|
accountKey: this._databaseBackup.blobs[i].storageKey,
|
||||||
blobContainerName: this._databaseBackup.blobs[i].blobContainer.name
|
blobContainerName: getBlobContainerNameWithFolder(this._databaseBackup.blobs[i], isOfflineMigration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1094,7 +1087,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
|||||||
if (isOfflineMigration) {
|
if (isOfflineMigration) {
|
||||||
requestBody.properties.offlineConfiguration = {
|
requestBody.properties.offlineConfiguration = {
|
||||||
offline: isOfflineMigration,
|
offline: isOfflineMigration,
|
||||||
lastBackupName: this._databaseBackup.blobs[i]?.lastBackupFile
|
lastBackupName: getLastBackupFileNameWithoutFolder(this._databaseBackup.blobs[i])
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import * as vscode from 'vscode';
|
|||||||
import { EOL } from 'os';
|
import { EOL } from 'os';
|
||||||
import { getStorageAccountAccessKeys, SqlVMServer } from '../api/azure';
|
import { getStorageAccountAccessKeys, SqlVMServer } from '../api/azure';
|
||||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||||
import { Blob, MigrationMode, MigrationSourceAuthenticationType, MigrationStateModel, MigrationTargetType, NetworkContainerType, NetworkShare, StateChangeEvent, ValidateIrState, ValidationResult } from '../models/stateMachine';
|
import { MigrationMode, MigrationSourceAuthenticationType, MigrationStateModel, MigrationTargetType, NetworkContainerType, NetworkShare, StateChangeEvent, ValidateIrState, ValidationResult } from '../models/stateMachine';
|
||||||
import * as constants from '../constants/strings';
|
import * as constants from '../constants/strings';
|
||||||
import { IconPathHelper } from '../constants/iconPathHelper';
|
import { IconPathHelper } from '../constants/iconPathHelper';
|
||||||
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
||||||
@@ -27,6 +27,7 @@ const blobResourceGroupErrorStrings = [constants.RESOURCE_GROUP_NOT_FOUND];
|
|||||||
const blobStorageAccountErrorStrings = [constants.NO_STORAGE_ACCOUNT_FOUND, constants.SELECT_RESOURCE_GROUP_PROMPT];
|
const blobStorageAccountErrorStrings = [constants.NO_STORAGE_ACCOUNT_FOUND, constants.SELECT_RESOURCE_GROUP_PROMPT];
|
||||||
const blobContainerErrorStrings = [constants.NO_BLOBCONTAINERS_FOUND, constants.SELECT_STORAGE_ACCOUNT];
|
const blobContainerErrorStrings = [constants.NO_BLOBCONTAINERS_FOUND, constants.SELECT_STORAGE_ACCOUNT];
|
||||||
const blobFileErrorStrings = [constants.NO_BLOBFILES_FOUND, constants.SELECT_BLOB_CONTAINER];
|
const blobFileErrorStrings = [constants.NO_BLOBFILES_FOUND, constants.SELECT_BLOB_CONTAINER];
|
||||||
|
const blobFolderErrorStrings = [constants.NO_BLOBFOLDERS_FOUND, constants.SELECT_BLOB_CONTAINER];
|
||||||
|
|
||||||
export class DatabaseBackupPage extends MigrationWizardPage {
|
export class DatabaseBackupPage extends MigrationWizardPage {
|
||||||
private _view!: azdata.ModelView;
|
private _view!: azdata.ModelView;
|
||||||
@@ -46,6 +47,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
private _blobContainerStorageAccountDropdowns!: azdata.DropDownComponent[];
|
private _blobContainerStorageAccountDropdowns!: azdata.DropDownComponent[];
|
||||||
private _blobContainerDropdowns!: azdata.DropDownComponent[];
|
private _blobContainerDropdowns!: azdata.DropDownComponent[];
|
||||||
private _blobContainerLastBackupFileDropdowns!: azdata.DropDownComponent[];
|
private _blobContainerLastBackupFileDropdowns!: azdata.DropDownComponent[];
|
||||||
|
private _blobContainerFolderDropdowns!: azdata.DropDownComponent[];
|
||||||
private _blobContainerVmDatabaseAlreadyExistsInfoBox!: azdata.TextComponent;
|
private _blobContainerVmDatabaseAlreadyExistsInfoBox!: azdata.TextComponent;
|
||||||
|
|
||||||
private _networkShareStorageAccountDetails!: azdata.FlexContainer;
|
private _networkShareStorageAccountDetails!: azdata.FlexContainer;
|
||||||
@@ -390,7 +392,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
rowCssStyles: rowCssStyle,
|
rowCssStyles: rowCssStyle,
|
||||||
headerCssStyles: headerCssStyles,
|
headerCssStyles: headerCssStyles,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
width: WIZARD_TABLE_COLUMN_WIDTH
|
width: WIZARD_TABLE_COLUMN_WIDTH_SMALL
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayName: constants.NETWORK_SHARE_PATH,
|
displayName: constants.NETWORK_SHARE_PATH,
|
||||||
@@ -412,7 +414,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
rowCssStyles: rowCssStyle,
|
rowCssStyles: rowCssStyle,
|
||||||
headerCssStyles: headerCssStyles,
|
headerCssStyles: headerCssStyles,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
width: WIZARD_TABLE_COLUMN_WIDTH,
|
width: WIZARD_TABLE_COLUMN_WIDTH_SMALL,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayName: constants.TARGET_DATABASE_NAME,
|
displayName: constants.TARGET_DATABASE_NAME,
|
||||||
@@ -420,7 +422,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
rowCssStyles: rowCssStyle,
|
rowCssStyles: rowCssStyle,
|
||||||
headerCssStyles: headerCssStyles,
|
headerCssStyles: headerCssStyles,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
width: WIZARD_TABLE_COLUMN_WIDTH
|
width: WIZARD_TABLE_COLUMN_WIDTH_SMALL
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayName: constants.RESOURCE_GROUP,
|
displayName: constants.RESOURCE_GROUP,
|
||||||
@@ -428,7 +430,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
rowCssStyles: rowCssStyle,
|
rowCssStyles: rowCssStyle,
|
||||||
headerCssStyles: headerCssStyles,
|
headerCssStyles: headerCssStyles,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
width: WIZARD_TABLE_COLUMN_WIDTH
|
width: WIZARD_TABLE_COLUMN_WIDTH_SMALL
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayName: constants.STORAGE_ACCOUNT,
|
displayName: constants.STORAGE_ACCOUNT,
|
||||||
@@ -436,7 +438,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
rowCssStyles: rowCssStyle,
|
rowCssStyles: rowCssStyle,
|
||||||
headerCssStyles: headerCssStyles,
|
headerCssStyles: headerCssStyles,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
width: WIZARD_TABLE_COLUMN_WIDTH
|
width: WIZARD_TABLE_COLUMN_WIDTH_SMALL
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayName: constants.BLOB_CONTAINER,
|
displayName: constants.BLOB_CONTAINER,
|
||||||
@@ -444,7 +446,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
rowCssStyles: rowCssStyle,
|
rowCssStyles: rowCssStyle,
|
||||||
headerCssStyles: headerCssStyles,
|
headerCssStyles: headerCssStyles,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
width: WIZARD_TABLE_COLUMN_WIDTH
|
width: WIZARD_TABLE_COLUMN_WIDTH_SMALL
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
displayName: constants.BLOB_CONTAINER_LAST_BACKUP_FILE,
|
displayName: constants.BLOB_CONTAINER_LAST_BACKUP_FILE,
|
||||||
@@ -452,9 +454,18 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
rowCssStyles: rowCssStyle,
|
rowCssStyles: rowCssStyle,
|
||||||
headerCssStyles: headerCssStyles,
|
headerCssStyles: headerCssStyles,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
width: WIZARD_TABLE_COLUMN_WIDTH,
|
width: WIZARD_TABLE_COLUMN_WIDTH_SMALL,
|
||||||
hidden: true
|
hidden: true
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
displayName: constants.BLOB_CONTAINER_FOLDER,
|
||||||
|
valueType: azdata.DeclarativeDataType.component,
|
||||||
|
rowCssStyles: rowCssStyle,
|
||||||
|
headerCssStyles: headerCssStyles,
|
||||||
|
isReadOnly: true,
|
||||||
|
width: WIZARD_TABLE_COLUMN_WIDTH_SMALL,
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
@@ -719,6 +730,12 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
errors.push(constants.INVALID_BLOB_LAST_BACKUP_FILE_ERROR(this.migrationStateModel._databasesForMigration[index]));
|
errors.push(constants.INVALID_BLOB_LAST_BACKUP_FILE_ERROR(this.migrationStateModel._databasesForMigration[index]));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
this._blobContainerFolderDropdowns.forEach((v, index) => {
|
||||||
|
if (this.shouldDisplayBlobDropdownError(v, blobFolderErrorStrings)) {
|
||||||
|
errors.push(constants.INVALID_BLOB_LAST_BACKUP_FOLDER_ERROR(this.migrationStateModel._databasesForMigration[index]));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.migrationStateModel.isSqlVmTarget && utils.isTargetSqlVm2014OrBelow(this.migrationStateModel._targetServerInstance as SqlVMServer)) {
|
if (this.migrationStateModel.isSqlVmTarget && utils.isTargetSqlVm2014OrBelow(this.migrationStateModel._targetServerInstance as SqlVMServer)) {
|
||||||
@@ -784,21 +801,32 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const isOfflineMigration = this.migrationStateModel._databaseBackup?.migrationMode === MigrationMode.OFFLINE;
|
const isOfflineMigration = this.migrationStateModel._databaseBackup?.migrationMode === MigrationMode.OFFLINE;
|
||||||
const lastBackupFileColumnIndex = this._blobContainerTargetDatabaseNamesTable.columns.length - 1;
|
|
||||||
const oldHidden = this._blobContainerTargetDatabaseNamesTable.columns[lastBackupFileColumnIndex].hidden;
|
// for offline migrations, show last backup file column
|
||||||
const newHidden = !isOfflineMigration;
|
const lastBackupFileColumnIndex = 5;
|
||||||
if (oldHidden !== newHidden) {
|
const lastBackupFileColumnOldHidden = this._blobContainerTargetDatabaseNamesTable.columns[lastBackupFileColumnIndex].hidden;
|
||||||
|
const lastBackupFileColumnNewHidden = !isOfflineMigration;
|
||||||
|
if (lastBackupFileColumnOldHidden !== lastBackupFileColumnNewHidden) {
|
||||||
// clear values prior to hiding columns if changing column visibility
|
// clear values prior to hiding columns if changing column visibility
|
||||||
// to prevent null DeclarativeTableComponent - exception / _view null
|
// to prevent null DeclarativeTableComponent - exception / _view null
|
||||||
await this._blobContainerTargetDatabaseNamesTable.setDataValues([]);
|
await this._blobContainerTargetDatabaseNamesTable.setDataValues([]);
|
||||||
}
|
}
|
||||||
|
this._blobContainerTargetDatabaseNamesTable.columns[lastBackupFileColumnIndex].hidden = lastBackupFileColumnNewHidden;
|
||||||
|
|
||||||
|
// for online migrations, show folder column
|
||||||
|
const folderColumnIndex = 6;
|
||||||
|
const folderColumnOldHidden = this._blobContainerTargetDatabaseNamesTable.columns[folderColumnIndex].hidden;
|
||||||
|
const folderColumnNewHidden = isOfflineMigration;
|
||||||
|
if (folderColumnOldHidden !== folderColumnNewHidden) {
|
||||||
|
// clear values prior to hiding columns if changing column visibility
|
||||||
|
// to prevent null DeclarativeTableComponent - exception / _view null
|
||||||
|
await this._blobContainerTargetDatabaseNamesTable.setDataValues([]);
|
||||||
|
}
|
||||||
|
this._blobContainerTargetDatabaseNamesTable.columns[folderColumnIndex].hidden = folderColumnNewHidden;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this._blobContainerTargetDatabaseNamesTable.columns[lastBackupFileColumnIndex].hidden = newHidden;
|
|
||||||
this._blobContainerTargetDatabaseNamesTable.columns.forEach(column => {
|
|
||||||
column.width = isOfflineMigration
|
|
||||||
? WIZARD_TABLE_COLUMN_WIDTH_SMALL
|
|
||||||
: WIZARD_TABLE_COLUMN_WIDTH;
|
|
||||||
});
|
|
||||||
|
|
||||||
const connectionProfile = await getSourceConnectionProfile();
|
const connectionProfile = await getSourceConnectionProfile();
|
||||||
const queryProvider = await getSourceConnectionQueryProvider();
|
const queryProvider = await getSourceConnectionQueryProvider();
|
||||||
@@ -841,6 +869,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
this._blobContainerStorageAccountDropdowns = [];
|
this._blobContainerStorageAccountDropdowns = [];
|
||||||
this._blobContainerDropdowns = [];
|
this._blobContainerDropdowns = [];
|
||||||
this._blobContainerLastBackupFileDropdowns = [];
|
this._blobContainerLastBackupFileDropdowns = [];
|
||||||
|
this._blobContainerFolderDropdowns = [];
|
||||||
|
|
||||||
if (this.migrationStateModel.isSqlMiTarget) {
|
if (this.migrationStateModel.isSqlMiTarget) {
|
||||||
this._existingDatabases = await this.migrationStateModel.getManagedDatabases();
|
this._existingDatabases = await this.migrationStateModel.getManagedDatabases();
|
||||||
@@ -862,7 +891,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
? this.migrationStateModel._sourceTargetMapping.get(sourceDatabaseName)?.databaseName ?? sourceDatabaseName
|
? this.migrationStateModel._sourceTargetMapping.get(sourceDatabaseName)?.databaseName ?? sourceDatabaseName
|
||||||
: sourceDatabaseName;
|
: sourceDatabaseName;
|
||||||
let networkShare = <NetworkShare>{};
|
let networkShare = <NetworkShare>{};
|
||||||
let blob = <Blob>{};
|
let blob = <utils.Blob>{};
|
||||||
|
|
||||||
if (this.migrationStateModel._didUpdateDatabasesForMigration ||
|
if (this.migrationStateModel._didUpdateDatabasesForMigration ||
|
||||||
this.migrationStateModel._didDatabaseMappingChange) {
|
this.migrationStateModel._didDatabaseMappingChange) {
|
||||||
@@ -1013,6 +1042,15 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
required: true,
|
required: true,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
}).component();
|
}).component();
|
||||||
|
const blobContainerFolderDropdown = this._view.modelBuilder.dropDown()
|
||||||
|
.withProps({
|
||||||
|
ariaLabel: constants.BLOB_CONTAINER_FOLDER,
|
||||||
|
editable: true,
|
||||||
|
fireOnTextChange: true,
|
||||||
|
required: true,
|
||||||
|
enabled: false,
|
||||||
|
}).component();
|
||||||
|
|
||||||
|
|
||||||
this._disposables.push(
|
this._disposables.push(
|
||||||
blobContainerResourceDropdown.onValueChanged(async (value) => {
|
blobContainerResourceDropdown.onValueChanged(async (value) => {
|
||||||
@@ -1070,6 +1108,9 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
if (this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE) {
|
if (this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE) {
|
||||||
await this.loadBlobLastBackupFileDropdown(index);
|
await this.loadBlobLastBackupFileDropdown(index);
|
||||||
await blobContainerLastBackupFileDropdown.updateProperties({ enabled: true });
|
await blobContainerLastBackupFileDropdown.updateProperties({ enabled: true });
|
||||||
|
} else {
|
||||||
|
await this.loadBlobFolderDropdown(index);
|
||||||
|
await blobContainerFolderDropdown.updateProperties({ enabled: true });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await this.disableBlobTableDropdowns(index, constants.BLOB_CONTAINER);
|
await this.disableBlobTableDropdowns(index, constants.BLOB_CONTAINER);
|
||||||
@@ -1091,6 +1132,17 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
this._blobContainerLastBackupFileDropdowns.push(blobContainerLastBackupFileDropdown);
|
this._blobContainerLastBackupFileDropdowns.push(blobContainerLastBackupFileDropdown);
|
||||||
|
} else {
|
||||||
|
this._disposables.push(
|
||||||
|
blobContainerFolderDropdown.onValueChanged(value => {
|
||||||
|
if (value && value !== 'undefined') {
|
||||||
|
if (this.migrationStateModel._blobContainerFolders.includes(value) && !blobFolderErrorStrings.includes(value)) {
|
||||||
|
const selectedFolder = value;
|
||||||
|
this.migrationStateModel._databaseBackup.blobs[index].folderName = selectedFolder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
this._blobContainerFolderDropdowns.push(blobContainerFolderDropdown);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.migrationStateModel._sourceDatabaseNames = this.migrationStateModel._databasesForMigration;
|
this.migrationStateModel._sourceDatabaseNames = this.migrationStateModel._databasesForMigration;
|
||||||
@@ -1109,7 +1161,8 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
{ value: this._blobContainerResourceGroupDropdowns[index] },
|
{ value: this._blobContainerResourceGroupDropdowns[index] },
|
||||||
{ value: this._blobContainerStorageAccountDropdowns[index] },
|
{ value: this._blobContainerStorageAccountDropdowns[index] },
|
||||||
{ value: this._blobContainerDropdowns[index] },
|
{ value: this._blobContainerDropdowns[index] },
|
||||||
{ value: this._blobContainerLastBackupFileDropdowns[index] }]);
|
{ value: this._blobContainerLastBackupFileDropdowns[index] },
|
||||||
|
{ value: this._blobContainerFolderDropdowns[index] }]);
|
||||||
await this._blobContainerTargetDatabaseNamesTable.setDataValues([]);
|
await this._blobContainerTargetDatabaseNamesTable.setDataValues([]);
|
||||||
await this._blobContainerTargetDatabaseNamesTable.setDataValues(blobContainerTargetData);
|
await this._blobContainerTargetDatabaseNamesTable.setDataValues(blobContainerTargetData);
|
||||||
await this.getSubscriptionValues();
|
await this.getSubscriptionValues();
|
||||||
@@ -1266,6 +1319,8 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
|
|
||||||
if (this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE) {
|
if (this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.OFFLINE) {
|
||||||
await this._blobContainerLastBackupFileDropdowns[i]?.validate();
|
await this._blobContainerLastBackupFileDropdowns[i]?.validate();
|
||||||
|
} else {
|
||||||
|
await this._blobContainerFolderDropdowns[i]?.validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.migrationStateModel.isIrMigration) {
|
if (this.migrationStateModel.isIrMigration) {
|
||||||
@@ -1420,7 +1475,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
this.migrationStateModel._databaseBackup.subscription,
|
this.migrationStateModel._databaseBackup.subscription,
|
||||||
this.migrationStateModel._databaseBackup.blobs[index]?.storageAccount,
|
this.migrationStateModel._databaseBackup.blobs[index]?.storageAccount,
|
||||||
this.migrationStateModel._databaseBackup.blobs[index]?.blobContainer);
|
this.migrationStateModel._databaseBackup.blobs[index]?.blobContainer);
|
||||||
dropDown.values = await utils.getBlobLastBackupFileNamesValues(
|
dropDown.values = utils.getBlobLastBackupFileNamesValues(
|
||||||
this.migrationStateModel._lastFileNames);
|
this.migrationStateModel._lastFileNames);
|
||||||
utils.selectDefaultDropdownValue(
|
utils.selectDefaultDropdownValue(
|
||||||
dropDown,
|
dropDown,
|
||||||
@@ -1434,6 +1489,28 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async loadBlobFolderDropdown(index: number): Promise<void> {
|
||||||
|
const dropDown = this._blobContainerFolderDropdowns[index];
|
||||||
|
if (dropDown) {
|
||||||
|
try {
|
||||||
|
dropDown.loading = true;
|
||||||
|
this.migrationStateModel._blobContainerFolders = await utils.getBlobFolders(this.migrationStateModel._azureAccount,
|
||||||
|
this.migrationStateModel._databaseBackup.subscription,
|
||||||
|
this.migrationStateModel._databaseBackup.blobs[index]?.storageAccount,
|
||||||
|
this.migrationStateModel._databaseBackup.blobs[index]?.blobContainer);
|
||||||
|
dropDown.values = utils.getBlobFolderValues(this.migrationStateModel._blobContainerFolders);
|
||||||
|
utils.selectDefaultDropdownValue(
|
||||||
|
dropDown,
|
||||||
|
this.migrationStateModel._blobContainerFolders[0],
|
||||||
|
false);
|
||||||
|
} catch (error) {
|
||||||
|
logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingBlobFolders', error);
|
||||||
|
} finally {
|
||||||
|
dropDown.loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private shouldDisplayBlobDropdownError(v: azdata.DropDownComponent, errorStrings: string[]) {
|
private shouldDisplayBlobDropdownError(v: azdata.DropDownComponent, errorStrings: string[]) {
|
||||||
return v.value === undefined || errorStrings.includes((<azdata.CategoryValue>v.value)?.displayName);
|
return v.value === undefined || errorStrings.includes((<azdata.CategoryValue>v.value)?.displayName);
|
||||||
}
|
}
|
||||||
@@ -1446,6 +1523,10 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
|||||||
this._blobContainerLastBackupFileDropdowns[rowIndex].values = createDropdownValuesWithPrereq(constants.SELECT_BLOB_CONTAINER);
|
this._blobContainerLastBackupFileDropdowns[rowIndex].values = createDropdownValuesWithPrereq(constants.SELECT_BLOB_CONTAINER);
|
||||||
utils.selectDropDownIndex(this._blobContainerLastBackupFileDropdowns[rowIndex], 0);
|
utils.selectDropDownIndex(this._blobContainerLastBackupFileDropdowns[rowIndex], 0);
|
||||||
await this._blobContainerLastBackupFileDropdowns[rowIndex]?.updateProperties(dropdownProps);
|
await this._blobContainerLastBackupFileDropdowns[rowIndex]?.updateProperties(dropdownProps);
|
||||||
|
} else {
|
||||||
|
this._blobContainerFolderDropdowns[rowIndex].values = createDropdownValuesWithPrereq(constants.SELECT_BLOB_CONTAINER);
|
||||||
|
utils.selectDropDownIndex(this._blobContainerFolderDropdowns[rowIndex], 0);
|
||||||
|
await this._blobContainerFolderDropdowns[rowIndex]?.updateProperties(dropdownProps);
|
||||||
}
|
}
|
||||||
if (columnName === constants.BLOB_CONTAINER) { return; }
|
if (columnName === constants.BLOB_CONTAINER) { return; }
|
||||||
|
|
||||||
|
|||||||
@@ -865,7 +865,7 @@ export class LoginMigrationTargetSelectionPage extends MigrationWizardPage {
|
|||||||
this._accountTenantDropdown.loading = true;
|
this._accountTenantDropdown.loading = true;
|
||||||
if (this.migrationStateModel._azureAccount && this.migrationStateModel._azureAccount.isStale === false && this.migrationStateModel._azureAccount.properties.tenants.length > 0) {
|
if (this.migrationStateModel._azureAccount && this.migrationStateModel._azureAccount.isStale === false && this.migrationStateModel._azureAccount.properties.tenants.length > 0) {
|
||||||
this.migrationStateModel._accountTenants = utils.getAzureTenants(this.migrationStateModel._azureAccount);
|
this.migrationStateModel._accountTenants = utils.getAzureTenants(this.migrationStateModel._azureAccount);
|
||||||
this._accountTenantDropdown.values = await utils.getAzureTenantsDropdownValues(this.migrationStateModel._accountTenants);
|
this._accountTenantDropdown.values = utils.getAzureTenantsDropdownValues(this.migrationStateModel._accountTenants);
|
||||||
}
|
}
|
||||||
utils.selectDefaultDropdownValue(
|
utils.selectDefaultDropdownValue(
|
||||||
this._accountTenantDropdown,
|
this._accountTenantDropdown,
|
||||||
@@ -929,7 +929,7 @@ export class LoginMigrationTargetSelectionPage extends MigrationWizardPage {
|
|||||||
this.migrationStateModel._targetSqlDatabaseServers);
|
this.migrationStateModel._targetSqlDatabaseServers);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this._azureLocationDropdown.values = await utils.getAzureLocationsDropdownValues(this.migrationStateModel._locations);
|
this._azureLocationDropdown.values = utils.getAzureLocationsDropdownValues(this.migrationStateModel._locations);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -890,7 +890,7 @@ export class TargetSelectionPage extends MigrationWizardPage {
|
|||||||
this.migrationStateModel._azureAccount?.properties?.tenants?.length > 0) {
|
this.migrationStateModel._azureAccount?.properties?.tenants?.length > 0) {
|
||||||
this.migrationStateModel._accountTenants = utils.getAzureTenants(this.migrationStateModel._azureAccount);
|
this.migrationStateModel._accountTenants = utils.getAzureTenants(this.migrationStateModel._azureAccount);
|
||||||
|
|
||||||
this._accountTenantDropdown.values = await utils.getAzureTenantsDropdownValues(this.migrationStateModel._accountTenants);
|
this._accountTenantDropdown.values = utils.getAzureTenantsDropdownValues(this.migrationStateModel._accountTenants);
|
||||||
}
|
}
|
||||||
const tenantId =
|
const tenantId =
|
||||||
this.migrationStateModel._azureTenant?.id ??
|
this.migrationStateModel._azureTenant?.id ??
|
||||||
@@ -963,7 +963,7 @@ export class TargetSelectionPage extends MigrationWizardPage {
|
|||||||
this.migrationStateModel._targetSqlDatabaseServers);
|
this.migrationStateModel._targetSqlDatabaseServers);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this._azureLocationDropdown.values = await utils.getAzureLocationsDropdownValues(this.migrationStateModel._locations);
|
this._azureLocationDropdown.values = utils.getAzureLocationsDropdownValues(this.migrationStateModel._locations);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user