mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
add delete migration method in migration list and details pages (#22243)
* add delete migraiton, fix stale token detection * address pr comments, fix api error response format
This commit is contained in:
@@ -88,6 +88,11 @@
|
|||||||
"title": "%cancel-migration-menu%",
|
"title": "%cancel-migration-menu%",
|
||||||
"category": "%migration-context-menu-category%"
|
"category": "%migration-context-menu-category%"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "sqlmigration.delete.migration",
|
||||||
|
"title": "%delete-migration-menu%",
|
||||||
|
"category": "%migration-context-menu-category%"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "sqlmigration.retry.migration",
|
"command": "sqlmigration.retry.migration",
|
||||||
"title": "%retry-migration-menu%",
|
"title": "%retry-migration-menu%",
|
||||||
@@ -128,6 +133,10 @@
|
|||||||
"command": "sqlmigration.cancel.migration",
|
"command": "sqlmigration.cancel.migration",
|
||||||
"when": "false"
|
"when": "false"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "sqlmigration.delete.migration",
|
||||||
|
"when": "false"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "sqlmigration.retry.migration",
|
"command": "sqlmigration.retry.migration",
|
||||||
"when": "false"
|
"when": "false"
|
||||||
|
|||||||
@@ -16,5 +16,6 @@
|
|||||||
"view-service-menu": "Database Migration Service details",
|
"view-service-menu": "Database Migration Service details",
|
||||||
"copy-migration-menu": "Copy migration details",
|
"copy-migration-menu": "Copy migration details",
|
||||||
"cancel-migration-menu": "Cancel migration",
|
"cancel-migration-menu": "Cancel migration",
|
||||||
|
"delete-migration-menu": "Delete migration",
|
||||||
"retry-migration-menu": "Retry migration"
|
"retry-migration-menu": "Retry migration"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,7 +286,11 @@ export async function getVMInstanceView(sqlVm: SqlVMServer, account: azdata.Acco
|
|||||||
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, host);
|
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, host);
|
||||||
|
|
||||||
if (response.errors.length > 0) {
|
if (response.errors.length > 0) {
|
||||||
throw new Error(response.errors.toString());
|
const message = response.errors
|
||||||
|
.map(err => err.message)
|
||||||
|
.join(', ');
|
||||||
|
throw new Error(message);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.response.data;
|
return response.response.data;
|
||||||
@@ -299,7 +303,11 @@ export async function getAzureResourceGivenId(account: azdata.Account, subscript
|
|||||||
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, host);
|
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, host);
|
||||||
|
|
||||||
if (response.errors.length > 0) {
|
if (response.errors.length > 0) {
|
||||||
throw new Error(response.errors.toString());
|
const message = response.errors
|
||||||
|
.map(err => err.message)
|
||||||
|
.join(', ');
|
||||||
|
throw new Error(message);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.response.data;
|
return response.response.data;
|
||||||
@@ -620,6 +628,19 @@ export async function stopMigration(account: azdata.Account, subscription: Subsc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function deleteMigration(account: azdata.Account, subscription: Subscription, migrationId: string): Promise<void> {
|
||||||
|
const api = await getAzureCoreAPI();
|
||||||
|
const path = encodeURI(`${migrationId}?api-version=${DMSV2_API_VERSION}`);
|
||||||
|
const host = api.getProviderMetadataForAccount(account).settings.armResource?.endpoint;
|
||||||
|
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.DELETE, undefined, true, host);
|
||||||
|
if (response.errors.length > 0) {
|
||||||
|
const message = response.errors
|
||||||
|
.map(err => err.message)
|
||||||
|
.join(', ');
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function getLocationDisplayName(location: string): Promise<string> {
|
export async function getLocationDisplayName(location: string): Promise<string> {
|
||||||
const api = await getAzureCoreAPI();
|
const api = await getAzureCoreAPI();
|
||||||
return api.getRegionDisplayName(location);
|
return api.getRegionDisplayName(location);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export const MenuCommands = {
|
|||||||
ViewService: 'sqlmigration.view.service',
|
ViewService: 'sqlmigration.view.service',
|
||||||
CopyMigration: 'sqlmigration.copy.migration',
|
CopyMigration: 'sqlmigration.copy.migration',
|
||||||
CancelMigration: 'sqlmigration.cancel.migration',
|
CancelMigration: 'sqlmigration.cancel.migration',
|
||||||
|
DeleteMigration: 'sqlmigration.delete.migration',
|
||||||
RetryMigration: 'sqlmigration.retry.migration',
|
RetryMigration: 'sqlmigration.retry.migration',
|
||||||
StartMigration: 'sqlmigration.start',
|
StartMigration: 'sqlmigration.start',
|
||||||
StartLoginMigration: 'sqlmigration.login.start',
|
StartLoginMigration: 'sqlmigration.login.start',
|
||||||
@@ -423,7 +424,7 @@ export async function getAzureAccountsDropdownValues(accounts: Account[]): Promi
|
|||||||
accounts.forEach((account) => {
|
accounts.forEach((account) => {
|
||||||
accountsValues.push({
|
accountsValues.push({
|
||||||
name: account.displayInfo.userId,
|
name: account.displayInfo.userId,
|
||||||
displayName: account.isStale
|
displayName: isAccountTokenStale(account)
|
||||||
? constants.ACCOUNT_CREDENTIALS_REFRESH(account.displayInfo.displayName)
|
? constants.ACCOUNT_CREDENTIALS_REFRESH(account.displayInfo.displayName)
|
||||||
: account.displayInfo.displayName
|
: account.displayInfo.displayName
|
||||||
});
|
});
|
||||||
@@ -439,6 +440,10 @@ export async function getAzureAccountsDropdownValues(accounts: Account[]): Promi
|
|||||||
return accountsValues;
|
return accountsValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAccountTokenStale(account: Account | undefined): boolean {
|
||||||
|
return account === undefined || account?.isStale === true;
|
||||||
|
}
|
||||||
|
|
||||||
export function getAzureTenants(account?: Account): Tenant[] {
|
export function getAzureTenants(account?: Account): Tenant[] {
|
||||||
return account?.properties.tenants || [];
|
return account?.properties.tenants || [];
|
||||||
}
|
}
|
||||||
@@ -446,9 +451,9 @@ export function getAzureTenants(account?: Account): Tenant[] {
|
|||||||
export async function getAzureSubscriptions(account?: Account): Promise<azureResource.AzureResourceSubscription[]> {
|
export async function getAzureSubscriptions(account?: Account): Promise<azureResource.AzureResourceSubscription[]> {
|
||||||
let subscriptions: azureResource.AzureResourceSubscription[] = [];
|
let subscriptions: azureResource.AzureResourceSubscription[] = [];
|
||||||
try {
|
try {
|
||||||
if (account) {
|
subscriptions = account && !isAccountTokenStale(account)
|
||||||
subscriptions = !account.isStale ? await azure.getSubscriptions(account) : [];
|
? await azure.getSubscriptions(account)
|
||||||
}
|
: [];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(TelemetryViews.Utils, 'utils.getAzureSubscriptions', e);
|
logError(TelemetryViews.Utils, 'utils.getAzureSubscriptions', e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -991,12 +991,15 @@ export const ALL_BACKUPS_RESTORED = localize('sql.migration.all.backups.restored
|
|||||||
export const ACTIVE_BACKUP_FILES = localize('sql.migration.active.backup.files', "Active backup files");
|
export const ACTIVE_BACKUP_FILES = localize('sql.migration.active.backup.files', "Active backup files");
|
||||||
export const MIGRATION_STATUS_REFRESH_ERROR = localize('sql.migration.cutover.status.refresh.error', 'An error occurred while refreshing the migration status.');
|
export const MIGRATION_STATUS_REFRESH_ERROR = localize('sql.migration.cutover.status.refresh.error', 'An error occurred while refreshing the migration status.');
|
||||||
export const MIGRATION_CANCELLATION_ERROR = localize('sql.migration.cancel.error', 'An error occurred while canceling the migration.');
|
export const MIGRATION_CANCELLATION_ERROR = localize('sql.migration.cancel.error', 'An error occurred while canceling the migration.');
|
||||||
|
export const MIGRATION_DELETE_ERROR = localize('sql.migration.delete.error', 'An error occurred while deleting the migration.');
|
||||||
|
|
||||||
export const STATUS = localize('sql.migration.status', "Status");
|
export const STATUS = localize('sql.migration.status', "Status");
|
||||||
export const BACKUP_START_TIME = localize('sql.migration.backup.start.time', "Backup start time");
|
export const BACKUP_START_TIME = localize('sql.migration.backup.start.time', "Backup start time");
|
||||||
export const FIRST_LSN = localize('sql.migration.first.lsn', "First LSN");
|
export const FIRST_LSN = localize('sql.migration.first.lsn', "First LSN");
|
||||||
export const LAST_LSN = localize('sql.migration.last.LSN', "Last LSN");
|
export const LAST_LSN = localize('sql.migration.last.LSN', "Last LSN");
|
||||||
export const CANNOT_START_CUTOVER_ERROR = localize('sql.migration.cannot.start.cutover.error', "The cutover process cannot start until all the migrations are done. To return the latest file status, refresh your browser window.");
|
export const CANNOT_START_CUTOVER_ERROR = localize('sql.migration.cannot.start.cutover.error', "The cutover process cannot start until all the migrations are done. To return the latest file status, refresh your browser window.");
|
||||||
export const CANCEL_MIGRATION = localize('sql.migration.cancel.migration', "Cancel migration");
|
export const CANCEL_MIGRATION = localize('sql.migration.cancel.migration', "Cancel migration");
|
||||||
|
export const DELETE_MIGRATION = localize('sql.migration.delete.migration', "Delete migration");
|
||||||
export function ACTIVE_BACKUP_FILES_ITEMS(fileCount: number) {
|
export function ACTIVE_BACKUP_FILES_ITEMS(fileCount: number) {
|
||||||
if (fileCount === 1) {
|
if (fileCount === 1) {
|
||||||
return localize('sql.migration.active.backup.files.items', "Active backup files (1 item)");
|
return localize('sql.migration.active.backup.files.items', "Active backup files (1 item)");
|
||||||
@@ -1007,6 +1010,8 @@ export function ACTIVE_BACKUP_FILES_ITEMS(fileCount: number) {
|
|||||||
export const COPY_MIGRATION_DETAILS = localize('sql.migration.copy.migration.details', "Copy migration details");
|
export const COPY_MIGRATION_DETAILS = localize('sql.migration.copy.migration.details', "Copy migration details");
|
||||||
export const DETAILS_COPIED = localize('sql.migration.details.copied', "Details copied");
|
export const DETAILS_COPIED = localize('sql.migration.details.copied', "Details copied");
|
||||||
export const CANCEL_MIGRATION_CONFIRMATION = localize('sql.cancel.migration.confirmation', "Are you sure you want to cancel this migration?");
|
export const CANCEL_MIGRATION_CONFIRMATION = localize('sql.cancel.migration.confirmation', "Are you sure you want to cancel this migration?");
|
||||||
|
export const DELETE_MIGRATION_CONFIRMATION = localize('sql.delete.migration.confirmation', "Are you sure you want to delete this migration?");
|
||||||
|
|
||||||
export const YES = localize('sql.migration.yes', "Yes");
|
export const YES = localize('sql.migration.yes', "Yes");
|
||||||
export const NO = localize('sql.migration.no', "No");
|
export const NO = localize('sql.migration.no', "No");
|
||||||
export const NA = localize('sql.migration.na', "N/A");
|
export const NA = localize('sql.migration.na', "N/A");
|
||||||
@@ -1047,6 +1052,7 @@ export function CUTOVER_IN_PROGRESS(dbName: string): string {
|
|||||||
return localize('sql.migration.cutover.in.progress', "Cutover in progress for database '{0}'", dbName);
|
return localize('sql.migration.cutover.in.progress', "Cutover in progress for database '{0}'", dbName);
|
||||||
}
|
}
|
||||||
export const MIGRATION_CANNOT_CANCEL = localize('sql.migration.cannot.cancel', 'Migration is not in progress and cannot be canceled.');
|
export const MIGRATION_CANNOT_CANCEL = localize('sql.migration.cannot.cancel', 'Migration is not in progress and cannot be canceled.');
|
||||||
|
export const MIGRATION_CANNOT_DELETE = localize('sql.migration.cannot.delete', 'Migration is currently in progress and cannot be deleted.');
|
||||||
export const MIGRATION_CANNOT_CUTOVER = localize('sql.migration.cannot.cutover', 'Migration is not in progress and cannot be cutover.');
|
export const MIGRATION_CANNOT_CUTOVER = localize('sql.migration.cannot.cutover', 'Migration is not in progress and cannot be cutover.');
|
||||||
export const FILE_NAME = localize('sql.migration.file.name', "File name");
|
export const FILE_NAME = localize('sql.migration.file.name', "File name");
|
||||||
export const SIZE_COLUMN_HEADER = localize('sql.migration.size.column.header', "Size");
|
export const SIZE_COLUMN_HEADER = localize('sql.migration.size.column.header', "Size");
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import * as vscode from 'vscode';
|
|||||||
import * as loc from '../constants/strings';
|
import * as loc from '../constants/strings';
|
||||||
import { getSqlServerName, getMigrationStatusImage } from '../api/utils';
|
import { getSqlServerName, getMigrationStatusImage } from '../api/utils';
|
||||||
import { logError, TelemetryViews } from '../telemetry';
|
import { logError, TelemetryViews } from '../telemetry';
|
||||||
import { canCancelMigration, canCutoverMigration, canRetryMigration, getMigrationStatusString, getMigrationTargetTypeEnum, isOfflineMigation } from '../constants/helper';
|
import { canCancelMigration, canCutoverMigration, canDeleteMigration, canRetryMigration, getMigrationStatusString, getMigrationTargetTypeEnum, isOfflineMigation } from '../constants/helper';
|
||||||
import { getResourceName } from '../api/azure';
|
import { getResourceName } from '../api/azure';
|
||||||
import { InfoFieldSchema, infoFieldWidth, MigrationDetailsTabBase, MigrationTargetTypeName } from './migrationDetailsTabBase';
|
import { InfoFieldSchema, infoFieldWidth, MigrationDetailsTabBase, MigrationTargetTypeName } from './migrationDetailsTabBase';
|
||||||
import { EmptySettingValue } from './tabBase';
|
import { EmptySettingValue } from './tabBase';
|
||||||
@@ -37,7 +37,7 @@ export class MigrationDetailsBlobContainerTab extends MigrationDetailsTabBase<Mi
|
|||||||
public async create(
|
public async create(
|
||||||
context: vscode.ExtensionContext,
|
context: vscode.ExtensionContext,
|
||||||
view: azdata.ModelView,
|
view: azdata.ModelView,
|
||||||
openMigrationsListFcn: () => Promise<void>,
|
openMigrationsListFcn: (refresh?: boolean) => Promise<void>,
|
||||||
statusBar: DashboardStatusBar,
|
statusBar: DashboardStatusBar,
|
||||||
): Promise<MigrationDetailsBlobContainerTab> {
|
): Promise<MigrationDetailsBlobContainerTab> {
|
||||||
|
|
||||||
@@ -115,6 +115,7 @@ export class MigrationDetailsBlobContainerTab extends MigrationDetailsTabBase<Mi
|
|||||||
|
|
||||||
this.cutoverButton.enabled = canCutoverMigration(migration);
|
this.cutoverButton.enabled = canCutoverMigration(migration);
|
||||||
this.cancelButton.enabled = canCancelMigration(migration);
|
this.cancelButton.enabled = canCancelMigration(migration);
|
||||||
|
this.deleteButton.enabled = canDeleteMigration(migration);
|
||||||
this.retryButton.enabled = canRetryMigration(migration);
|
this.retryButton.enabled = canRetryMigration(migration);
|
||||||
|
|
||||||
this.refreshLoader.loading = false;
|
this.refreshLoader.loading = false;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import * as loc from '../constants/strings';
|
|||||||
import { convertByteSizeToReadableUnit, convertIsoTimeToLocalTime, getSqlServerName, getMigrationStatusImage } from '../api/utils';
|
import { convertByteSizeToReadableUnit, convertIsoTimeToLocalTime, getSqlServerName, getMigrationStatusImage } from '../api/utils';
|
||||||
import { logError, TelemetryViews } from '../telemetry';
|
import { logError, TelemetryViews } from '../telemetry';
|
||||||
import * as styles from '../constants/styles';
|
import * as styles from '../constants/styles';
|
||||||
import { canCancelMigration, canCutoverMigration, canRetryMigration, getMigrationStatusString, getMigrationTargetTypeEnum, isOfflineMigation } from '../constants/helper';
|
import { canCancelMigration, canCutoverMigration, canDeleteMigration, canRetryMigration, getMigrationStatusString, getMigrationTargetTypeEnum, isOfflineMigation } from '../constants/helper';
|
||||||
import { getResourceName } from '../api/azure';
|
import { getResourceName } from '../api/azure';
|
||||||
import { EmptySettingValue } from './tabBase';
|
import { EmptySettingValue } from './tabBase';
|
||||||
import { InfoFieldSchema, infoFieldWidth, MigrationDetailsTabBase, MigrationTargetTypeName } from './migrationDetailsTabBase';
|
import { InfoFieldSchema, infoFieldWidth, MigrationDetailsTabBase, MigrationTargetTypeName } from './migrationDetailsTabBase';
|
||||||
@@ -56,7 +56,7 @@ export class MigrationDetailsFileShareTab extends MigrationDetailsTabBase<Migrat
|
|||||||
public async create(
|
public async create(
|
||||||
context: vscode.ExtensionContext,
|
context: vscode.ExtensionContext,
|
||||||
view: azdata.ModelView,
|
view: azdata.ModelView,
|
||||||
openMigrationsListFcn: () => Promise<void>,
|
openMigrationsListFcn: (refresh?: boolean) => Promise<void>,
|
||||||
statusBar: DashboardStatusBar): Promise<MigrationDetailsFileShareTab> {
|
statusBar: DashboardStatusBar): Promise<MigrationDetailsFileShareTab> {
|
||||||
|
|
||||||
this.view = view;
|
this.view = view;
|
||||||
@@ -182,6 +182,7 @@ export class MigrationDetailsFileShareTab extends MigrationDetailsTabBase<Migrat
|
|||||||
|
|
||||||
this.cutoverButton.enabled = canCutoverMigration(migration);
|
this.cutoverButton.enabled = canCutoverMigration(migration);
|
||||||
this.cancelButton.enabled = canCancelMigration(migration);
|
this.cancelButton.enabled = canCancelMigration(migration);
|
||||||
|
this.deleteButton.enabled = canDeleteMigration(migration);
|
||||||
this.retryButton.enabled = canRetryMigration(migration);
|
this.retryButton.enabled = canRetryMigration(migration);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await this.statusBar.showError(
|
await this.statusBar.showError(
|
||||||
|
|||||||
@@ -9,13 +9,16 @@ import { IconPathHelper } from '../constants/iconPathHelper';
|
|||||||
import { MigrationServiceContext } from '../models/migrationLocalStorage';
|
import { MigrationServiceContext } from '../models/migrationLocalStorage';
|
||||||
import * as loc from '../constants/strings';
|
import * as loc from '../constants/strings';
|
||||||
import * as styles from '../constants/styles';
|
import * as styles from '../constants/styles';
|
||||||
import { DatabaseMigration } from '../api/azure';
|
import { DatabaseMigration, deleteMigration } from '../api/azure';
|
||||||
import { TabBase } from './tabBase';
|
import { TabBase } from './tabBase';
|
||||||
import { MigrationCutoverDialogModel } from '../dialog/migrationCutover/migrationCutoverDialogModel';
|
import { MigrationCutoverDialogModel } from '../dialog/migrationCutover/migrationCutoverDialogModel';
|
||||||
import { ConfirmCutoverDialog } from '../dialog/migrationCutover/confirmCutoverDialog';
|
import { ConfirmCutoverDialog } from '../dialog/migrationCutover/confirmCutoverDialog';
|
||||||
import { RetryMigrationDialog } from '../dialog/retryMigration/retryMigrationDialog';
|
import { RetryMigrationDialog } from '../dialog/retryMigration/retryMigrationDialog';
|
||||||
import { MigrationTargetType } from '../models/stateMachine';
|
import { MigrationTargetType } from '../models/stateMachine';
|
||||||
import { DashboardStatusBar } from './DashboardStatusBar';
|
import { DashboardStatusBar } from './DashboardStatusBar';
|
||||||
|
import { canDeleteMigration } from '../constants/helper';
|
||||||
|
import { logError, TelemetryViews } from '../telemetry';
|
||||||
|
import { MenuCommands } from '../api/utils';
|
||||||
|
|
||||||
export const infoFieldLgWidth: string = '330px';
|
export const infoFieldLgWidth: string = '330px';
|
||||||
export const infoFieldWidth: string = '250px';
|
export const infoFieldWidth: string = '250px';
|
||||||
@@ -38,10 +41,11 @@ export abstract class MigrationDetailsTabBase<T> extends TabBase<T> {
|
|||||||
protected model!: MigrationCutoverDialogModel;
|
protected model!: MigrationCutoverDialogModel;
|
||||||
protected databaseLabel!: azdata.TextComponent;
|
protected databaseLabel!: azdata.TextComponent;
|
||||||
protected serviceContext!: MigrationServiceContext;
|
protected serviceContext!: MigrationServiceContext;
|
||||||
protected openMigrationsListFcn!: () => Promise<void>;
|
protected openMigrationsListFcn!: (refresh?: boolean) => Promise<void>;
|
||||||
protected cutoverButton!: azdata.ButtonComponent;
|
protected cutoverButton!: azdata.ButtonComponent;
|
||||||
protected refreshButton!: azdata.ButtonComponent;
|
protected refreshButton!: azdata.ButtonComponent;
|
||||||
protected cancelButton!: azdata.ButtonComponent;
|
protected cancelButton!: azdata.ButtonComponent;
|
||||||
|
protected deleteButton!: azdata.ButtonComponent;
|
||||||
protected refreshLoader!: azdata.LoadingComponent;
|
protected refreshLoader!: azdata.LoadingComponent;
|
||||||
protected copyDatabaseMigrationDetails!: azdata.ButtonComponent;
|
protected copyDatabaseMigrationDetails!: azdata.ButtonComponent;
|
||||||
protected newSupportRequest!: azdata.ButtonComponent;
|
protected newSupportRequest!: azdata.ButtonComponent;
|
||||||
@@ -51,7 +55,7 @@ export abstract class MigrationDetailsTabBase<T> extends TabBase<T> {
|
|||||||
public abstract create(
|
public abstract create(
|
||||||
context: vscode.ExtensionContext,
|
context: vscode.ExtensionContext,
|
||||||
view: azdata.ModelView,
|
view: azdata.ModelView,
|
||||||
openMigrationsListFcn: () => Promise<void>,
|
openMigrationsListFcn: (refresh?: boolean) => Promise<void>,
|
||||||
statusBar: DashboardStatusBar): Promise<T>;
|
statusBar: DashboardStatusBar): Promise<T>;
|
||||||
|
|
||||||
protected abstract migrationInfoGrid(): Promise<azdata.FlexContainer>;
|
protected abstract migrationInfoGrid(): Promise<azdata.FlexContainer>;
|
||||||
@@ -186,6 +190,46 @@ export abstract class MigrationDetailsTabBase<T> extends TabBase<T> {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this.deleteButton = this.view.modelBuilder.button()
|
||||||
|
.withProps({
|
||||||
|
iconPath: IconPathHelper.discard,
|
||||||
|
iconHeight: '16px',
|
||||||
|
iconWidth: '16px',
|
||||||
|
label: loc.DELETE_MIGRATION,
|
||||||
|
height: buttonHeight,
|
||||||
|
enabled: false,
|
||||||
|
}).component();
|
||||||
|
|
||||||
|
this.disposables.push(
|
||||||
|
this.deleteButton.onDidClick(
|
||||||
|
async (e) => {
|
||||||
|
await this.statusBar.clearError();
|
||||||
|
try {
|
||||||
|
if (canDeleteMigration(this.model.migration)) {
|
||||||
|
const response = await vscode.window.showInformationMessage(
|
||||||
|
loc.DELETE_MIGRATION_CONFIRMATION,
|
||||||
|
{ modal: true },
|
||||||
|
loc.YES,
|
||||||
|
loc.NO);
|
||||||
|
if (response === loc.YES) {
|
||||||
|
await deleteMigration(
|
||||||
|
this.serviceContext.azureAccount!,
|
||||||
|
this.serviceContext.subscription!,
|
||||||
|
this.model.migration.id);
|
||||||
|
await this.openMigrationsListFcn(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_DELETE);
|
||||||
|
logError(TelemetryViews.MigrationDetailsTab, MenuCommands.DeleteMigration, "cannot delete migration");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
await this.statusBar.showError(
|
||||||
|
loc.MIGRATION_DELETE_ERROR,
|
||||||
|
loc.MIGRATION_DELETE_ERROR,
|
||||||
|
e.message);
|
||||||
|
logError(TelemetryViews.MigrationDetailsTab, MenuCommands.DeleteMigration, e);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
this.retryButton = this.view.modelBuilder.button()
|
this.retryButton = this.view.modelBuilder.button()
|
||||||
.withProps({
|
.withProps({
|
||||||
@@ -266,6 +310,7 @@ export abstract class MigrationDetailsTabBase<T> extends TabBase<T> {
|
|||||||
toolbarContainer.addToolbarItems([
|
toolbarContainer.addToolbarItems([
|
||||||
<azdata.ToolbarComponent>{ component: this.cutoverButton },
|
<azdata.ToolbarComponent>{ component: this.cutoverButton },
|
||||||
<azdata.ToolbarComponent>{ component: this.cancelButton },
|
<azdata.ToolbarComponent>{ component: this.cancelButton },
|
||||||
|
<azdata.ToolbarComponent>{ component: this.deleteButton },
|
||||||
<azdata.ToolbarComponent>{ component: this.retryButton },
|
<azdata.ToolbarComponent>{ component: this.retryButton },
|
||||||
<azdata.ToolbarComponent>{ component: this.copyDatabaseMigrationDetails, toolbarSeparatorAfter: true },
|
<azdata.ToolbarComponent>{ component: this.copyDatabaseMigrationDetails, toolbarSeparatorAfter: true },
|
||||||
<azdata.ToolbarComponent>{ component: this.newSupportRequest, toolbarSeparatorAfter: true },
|
<azdata.ToolbarComponent>{ component: this.newSupportRequest, toolbarSeparatorAfter: true },
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import * as vscode from 'vscode';
|
|||||||
import * as loc from '../constants/strings';
|
import * as loc from '../constants/strings';
|
||||||
import { getSqlServerName, getMigrationStatusImage, getPipelineStatusImage, debounce } from '../api/utils';
|
import { getSqlServerName, getMigrationStatusImage, getPipelineStatusImage, debounce } from '../api/utils';
|
||||||
import { logError, TelemetryViews } from '../telemetry';
|
import { logError, TelemetryViews } from '../telemetry';
|
||||||
import { canCancelMigration, canCutoverMigration, canRetryMigration, formatDateTimeString, formatNumber, formatSizeBytes, formatSizeKb, formatTime, getMigrationStatusString, getMigrationTargetTypeEnum, isOfflineMigation, PipelineStatusCodes } from '../constants/helper';
|
import { canCancelMigration, canCutoverMigration, canDeleteMigration, canRetryMigration, formatDateTimeString, formatNumber, formatSizeBytes, formatSizeKb, formatTime, getMigrationStatusString, getMigrationTargetTypeEnum, isOfflineMigation, PipelineStatusCodes } from '../constants/helper';
|
||||||
import { CopyProgressDetail, getResourceName } from '../api/azure';
|
import { CopyProgressDetail, getResourceName } from '../api/azure';
|
||||||
import { InfoFieldSchema, infoFieldLgWidth, MigrationDetailsTabBase, MigrationTargetTypeName } from './migrationDetailsTabBase';
|
import { InfoFieldSchema, infoFieldLgWidth, MigrationDetailsTabBase, MigrationTargetTypeName } from './migrationDetailsTabBase';
|
||||||
import { IconPathHelper } from '../constants/iconPathHelper';
|
import { IconPathHelper } from '../constants/iconPathHelper';
|
||||||
@@ -63,7 +63,7 @@ export class MigrationDetailsTableTab extends MigrationDetailsTabBase<MigrationD
|
|||||||
public async create(
|
public async create(
|
||||||
context: vscode.ExtensionContext,
|
context: vscode.ExtensionContext,
|
||||||
view: azdata.ModelView,
|
view: azdata.ModelView,
|
||||||
openMigrationsListFcn: () => Promise<void>,
|
openMigrationsListFcn: (refresh?: boolean) => Promise<void>,
|
||||||
statusBar: DashboardStatusBar): Promise<MigrationDetailsTableTab> {
|
statusBar: DashboardStatusBar): Promise<MigrationDetailsTableTab> {
|
||||||
|
|
||||||
this.view = view;
|
this.view = view;
|
||||||
@@ -162,6 +162,7 @@ export class MigrationDetailsTableTab extends MigrationDetailsTabBase<MigrationD
|
|||||||
|
|
||||||
this.cutoverButton.enabled = canCutoverMigration(migration);
|
this.cutoverButton.enabled = canCutoverMigration(migration);
|
||||||
this.cancelButton.enabled = canCancelMigration(migration);
|
this.cancelButton.enabled = canCancelMigration(migration);
|
||||||
|
this.deleteButton.enabled = canDeleteMigration(migration);
|
||||||
this.retryButton.enabled = canRetryMigration(migration);
|
this.retryButton.enabled = canRetryMigration(migration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { IconPathHelper } from '../constants/iconPathHelper';
|
|||||||
import { getCurrentMigrations, getSelectedServiceStatus } from '../models/migrationLocalStorage';
|
import { getCurrentMigrations, getSelectedServiceStatus } from '../models/migrationLocalStorage';
|
||||||
import * as loc from '../constants/strings';
|
import * as loc from '../constants/strings';
|
||||||
import { filterMigrations, getMigrationDuration, getMigrationStatusImage, getMigrationStatusWithErrors, getMigrationTime, MenuCommands } from '../api/utils';
|
import { filterMigrations, getMigrationDuration, getMigrationStatusImage, getMigrationStatusWithErrors, getMigrationTime, MenuCommands } from '../api/utils';
|
||||||
import { getMigrationTargetType, getMigrationMode, canCancelMigration, canCutoverMigration } from '../constants/helper';
|
import { getMigrationTargetType, getMigrationMode, canCancelMigration, canCutoverMigration, canDeleteMigration } from '../constants/helper';
|
||||||
import { DatabaseMigration, getResourceName } from '../api/azure';
|
import { DatabaseMigration, getResourceName } from '../api/azure';
|
||||||
import { logError, TelemetryViews } from '../telemetry';
|
import { logError, TelemetryViews } from '../telemetry';
|
||||||
import { SelectMigrationServiceDialog } from '../dialog/selectMigrationService/selectMigrationServiceDialog';
|
import { SelectMigrationServiceDialog } from '../dialog/selectMigrationService/selectMigrationServiceDialog';
|
||||||
@@ -598,6 +598,10 @@ export class MigrationsListTab extends TabBase<MigrationsListTab> {
|
|||||||
menuCommands.push(MenuCommands.CancelMigration);
|
menuCommands.push(MenuCommands.CancelMigration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (canDeleteMigration(migration)) {
|
||||||
|
menuCommands.push(MenuCommands.DeleteMigration);
|
||||||
|
}
|
||||||
|
|
||||||
return menuCommands;
|
return menuCommands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,9 +85,12 @@ export class MigrationsTab extends TabBase<MigrationsTab> {
|
|||||||
this.statusBar);
|
this.statusBar);
|
||||||
this.disposables.push(this._migrationsListTab);
|
this.disposables.push(this._migrationsListTab);
|
||||||
|
|
||||||
const openMigrationsListTab = async (): Promise<void> => {
|
const openMigrationsListTab = async (refresh?: boolean): Promise<void> => {
|
||||||
await this.statusBar.clearError();
|
await this.statusBar.clearError();
|
||||||
await this._openTab(this._migrationsListTab);
|
await this._openTab(this._migrationsListTab);
|
||||||
|
if (refresh) {
|
||||||
|
await this._migrationsListTab.refresh();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this._migrationDetailsBlobTab = await new MigrationDetailsBlobContainerTab().create(
|
this._migrationDetailsBlobTab = await new MigrationDetailsBlobContainerTab().create(
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import { DatabaseMigration, getMigrationDetails } from '../api/azure';
|
import { DatabaseMigration, deleteMigration, getMigrationDetails } from '../api/azure';
|
||||||
import { MenuCommands, SqlMigrationExtensionId } from '../api/utils';
|
import { MenuCommands, SqlMigrationExtensionId } from '../api/utils';
|
||||||
import { canCancelMigration, canCutoverMigration, canRetryMigration } from '../constants/helper';
|
import { canCancelMigration, canCutoverMigration, canDeleteMigration, canRetryMigration } from '../constants/helper';
|
||||||
import { IconPathHelper } from '../constants/iconPathHelper';
|
import { IconPathHelper } from '../constants/iconPathHelper';
|
||||||
import { MigrationNotebookInfo, NotebookPathHelper } from '../constants/notebookPathHelper';
|
import { MigrationNotebookInfo, NotebookPathHelper } from '../constants/notebookPathHelper';
|
||||||
import * as loc from '../constants/strings';
|
import * as loc from '../constants/strings';
|
||||||
@@ -41,6 +41,7 @@ export class DashboardWidget {
|
|||||||
private readonly _onServiceContextChanged: vscode.EventEmitter<ServiceContextChangeEvent>;
|
private readonly _onServiceContextChanged: vscode.EventEmitter<ServiceContextChangeEvent>;
|
||||||
private readonly _migrationDetailsEvent: vscode.EventEmitter<MigrationDetailsEvent>;
|
private readonly _migrationDetailsEvent: vscode.EventEmitter<MigrationDetailsEvent>;
|
||||||
private readonly _errorEvent: vscode.EventEmitter<ErrorEvent>;
|
private readonly _errorEvent: vscode.EventEmitter<ErrorEvent>;
|
||||||
|
private _migrationsTab!: MigrationsTab;
|
||||||
|
|
||||||
constructor(context: vscode.ExtensionContext) {
|
constructor(context: vscode.ExtensionContext) {
|
||||||
this._context = context;
|
this._context = context;
|
||||||
@@ -94,11 +95,11 @@ export class DashboardWidget {
|
|||||||
if (!migrationsTabInitialized) {
|
if (!migrationsTabInitialized) {
|
||||||
migrationsTabInitialized = true;
|
migrationsTabInitialized = true;
|
||||||
tabs.selectTab(MigrationsTabId);
|
tabs.selectTab(MigrationsTabId);
|
||||||
await migrationsTab.setMigrationFilter(AdsMigrationStatus.ALL);
|
await this._migrationsTab.setMigrationFilter(AdsMigrationStatus.ALL);
|
||||||
await migrationsTab.refresh();
|
await this._migrationsTab.refresh();
|
||||||
await migrationsTab.setMigrationFilter(filter);
|
await this._migrationsTab.setMigrationFilter(filter);
|
||||||
} else {
|
} else {
|
||||||
const promise = migrationsTab.setMigrationFilter(filter);
|
const promise = this._migrationsTab.setMigrationFilter(filter);
|
||||||
tabs.selectTab(MigrationsTabId);
|
tabs.selectTab(MigrationsTabId);
|
||||||
await promise;
|
await promise;
|
||||||
}
|
}
|
||||||
@@ -111,16 +112,16 @@ export class DashboardWidget {
|
|||||||
statusBar);
|
statusBar);
|
||||||
disposables.push(dashboardTab);
|
disposables.push(dashboardTab);
|
||||||
|
|
||||||
const migrationsTab = await new MigrationsTab().create(
|
this._migrationsTab = await new MigrationsTab().create(
|
||||||
this._context,
|
this._context,
|
||||||
view,
|
view,
|
||||||
this._onServiceContextChanged,
|
this._onServiceContextChanged,
|
||||||
this._migrationDetailsEvent,
|
this._migrationDetailsEvent,
|
||||||
statusBar);
|
statusBar);
|
||||||
disposables.push(migrationsTab);
|
disposables.push(this._migrationsTab);
|
||||||
|
|
||||||
const tabs = view.modelBuilder.tabbedPanel()
|
const tabs = view.modelBuilder.tabbedPanel()
|
||||||
.withTabs([dashboardTab, migrationsTab])
|
.withTabs([dashboardTab, this._migrationsTab])
|
||||||
.withLayout({ alwaysShowTabs: true, orientation: azdata.TabOrientation.Horizontal })
|
.withLayout({ alwaysShowTabs: true, orientation: azdata.TabOrientation.Horizontal })
|
||||||
.withProps({
|
.withProps({
|
||||||
CSSStyles: {
|
CSSStyles: {
|
||||||
@@ -137,7 +138,7 @@ export class DashboardWidget {
|
|||||||
await this.clearError(await getSourceConnectionId());
|
await this.clearError(await getSourceConnectionId());
|
||||||
if (tabId === MigrationsTabId && !migrationsTabInitialized) {
|
if (tabId === MigrationsTabId && !migrationsTabInitialized) {
|
||||||
migrationsTabInitialized = true;
|
migrationsTabInitialized = true;
|
||||||
await migrationsTab.refresh();
|
await this._migrationsTab.refresh();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -210,8 +211,10 @@ export class DashboardWidget {
|
|||||||
async (args: MenuCommandArgs) => {
|
async (args: MenuCommandArgs) => {
|
||||||
try {
|
try {
|
||||||
const migration = await this._getMigrationById(args.migrationId, args.migrationOperationId);
|
const migration = await this._getMigrationById(args.migrationId, args.migrationOperationId);
|
||||||
const url = 'https://portal.azure.com/#resource/' + migration!.properties.scope;
|
if (migration) {
|
||||||
await vscode.env.openExternal(vscode.Uri.parse(url));
|
const url = 'https://portal.azure.com/#resource/' + migration.properties.scope;
|
||||||
|
await vscode.env.openExternal(vscode.Uri.parse(url));
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await this.showError(
|
await this.showError(
|
||||||
args.connectionId,
|
args.connectionId,
|
||||||
@@ -229,10 +232,13 @@ export class DashboardWidget {
|
|||||||
try {
|
try {
|
||||||
await this.clearError(args.connectionId);
|
await this.clearError(args.connectionId);
|
||||||
const migration = await this._getMigrationById(args.migrationId, args.migrationOperationId);
|
const migration = await this._getMigrationById(args.migrationId, args.migrationOperationId);
|
||||||
const dialog = new SqlMigrationServiceDetailsDialog(
|
const serviceContext = await MigrationLocalStorage.getMigrationServiceContext();
|
||||||
await MigrationLocalStorage.getMigrationServiceContext(),
|
if (migration && serviceContext) {
|
||||||
migration!);
|
const dialog = new SqlMigrationServiceDetailsDialog(
|
||||||
await dialog.initialize();
|
serviceContext,
|
||||||
|
migration);
|
||||||
|
await dialog.initialize();
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await this.showError(
|
await this.showError(
|
||||||
args.connectionId,
|
args.connectionId,
|
||||||
@@ -269,40 +275,81 @@ export class DashboardWidget {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._context.subscriptions.push(vscode.commands.registerCommand(
|
this._context.subscriptions.push(
|
||||||
MenuCommands.CancelMigration,
|
vscode.commands.registerCommand(
|
||||||
async (args: MenuCommandArgs) => {
|
MenuCommands.CancelMigration,
|
||||||
try {
|
async (args: MenuCommandArgs) => {
|
||||||
await this.clearError(args.connectionId);
|
try {
|
||||||
const migration = await this._getMigrationById(args.migrationId, args.migrationOperationId);
|
await this.clearError(args.connectionId);
|
||||||
if (canCancelMigration(migration)) {
|
const migration = await this._getMigrationById(args.migrationId, args.migrationOperationId);
|
||||||
void vscode.window.showInformationMessage(loc.CANCEL_MIGRATION_CONFIRMATION, loc.YES, loc.NO)
|
if (migration && canCancelMigration(migration)) {
|
||||||
.then(async (v) => {
|
void vscode.window
|
||||||
if (v === loc.YES) {
|
.showInformationMessage(loc.CANCEL_MIGRATION_CONFIRMATION, loc.YES, loc.NO)
|
||||||
const cutoverDialogModel = new MigrationCutoverDialogModel(
|
.then(async (v) => {
|
||||||
await MigrationLocalStorage.getMigrationServiceContext(),
|
if (v === loc.YES) {
|
||||||
migration!);
|
const cutoverDialogModel = new MigrationCutoverDialogModel(
|
||||||
await cutoverDialogModel.fetchStatus();
|
await MigrationLocalStorage.getMigrationServiceContext(),
|
||||||
await cutoverDialogModel.cancelMigration();
|
migration!);
|
||||||
|
await cutoverDialogModel.fetchStatus();
|
||||||
|
await cutoverDialogModel.cancelMigration();
|
||||||
|
|
||||||
if (cutoverDialogModel.CancelMigrationError) {
|
if (cutoverDialogModel.CancelMigrationError) {
|
||||||
void vscode.window.showErrorMessage(loc.MIGRATION_CANNOT_CANCEL);
|
void vscode.window.showErrorMessage(loc.MIGRATION_CANNOT_CANCEL);
|
||||||
logError(TelemetryViews.MigrationsTab, MenuCommands.CancelMigration, cutoverDialogModel.CancelMigrationError);
|
logError(TelemetryViews.MigrationsTab, MenuCommands.CancelMigration, cutoverDialogModel.CancelMigrationError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
} else {
|
||||||
} else {
|
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_CANCEL);
|
||||||
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_CANCEL);
|
}
|
||||||
|
} catch (e) {
|
||||||
|
await this.showError(
|
||||||
|
args.connectionId,
|
||||||
|
loc.MIGRATION_CANCELLATION_ERROR,
|
||||||
|
loc.MIGRATION_CANCELLATION_ERROR,
|
||||||
|
e.message);
|
||||||
|
logError(TelemetryViews.MigrationsTab, MenuCommands.CancelMigration, e);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
}));
|
||||||
await this.showError(
|
|
||||||
args.connectionId,
|
this._context.subscriptions.push(
|
||||||
loc.MIGRATION_CANCELLATION_ERROR,
|
vscode.commands.registerCommand(
|
||||||
loc.MIGRATION_CANCELLATION_ERROR,
|
MenuCommands.DeleteMigration,
|
||||||
e.message);
|
async (args: MenuCommandArgs) => {
|
||||||
logError(TelemetryViews.MigrationsTab, MenuCommands.CancelMigration, e);
|
await this.clearError(args.connectionId);
|
||||||
}
|
try {
|
||||||
}));
|
const service = await MigrationLocalStorage.getMigrationServiceContext();
|
||||||
|
const migration = await this._getMigrationById(args.migrationId, args.migrationOperationId);
|
||||||
|
// get migration details can return undefined when the migration has been auto-cleaned
|
||||||
|
// however, since the migration is still returned in getlist, we make a best effort to delete by id.
|
||||||
|
if (service && (
|
||||||
|
(migration && canDeleteMigration(migration)) ||
|
||||||
|
(migration === undefined && args.migrationId?.length > 0))) {
|
||||||
|
const response = await vscode.window.showInformationMessage(
|
||||||
|
loc.DELETE_MIGRATION_CONFIRMATION,
|
||||||
|
{ modal: true },
|
||||||
|
loc.YES,
|
||||||
|
loc.NO);
|
||||||
|
if (response === loc.YES) {
|
||||||
|
await deleteMigration(
|
||||||
|
service.azureAccount!,
|
||||||
|
service.subscription!,
|
||||||
|
args.migrationId);
|
||||||
|
await this._migrationsTab.refresh();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_DELETE);
|
||||||
|
logError(TelemetryViews.MigrationsTab, MenuCommands.DeleteMigration, "cannot delete migration");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
await this.showError(
|
||||||
|
args.connectionId,
|
||||||
|
loc.MIGRATION_DELETE_ERROR,
|
||||||
|
loc.MIGRATION_DELETE_ERROR,
|
||||||
|
e.message);
|
||||||
|
logError(TelemetryViews.MigrationsTab, MenuCommands.DeleteMigration, e);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
this._context.subscriptions.push(
|
this._context.subscriptions.push(
|
||||||
vscode.commands.registerCommand(
|
vscode.commands.registerCommand(
|
||||||
@@ -311,11 +358,11 @@ export class DashboardWidget {
|
|||||||
try {
|
try {
|
||||||
await this.clearError(args.connectionId);
|
await this.clearError(args.connectionId);
|
||||||
const migration = await this._getMigrationById(args.migrationId, args.migrationOperationId);
|
const migration = await this._getMigrationById(args.migrationId, args.migrationOperationId);
|
||||||
if (canRetryMigration(migration)) {
|
if (migration && canRetryMigration(migration)) {
|
||||||
const retryMigrationDialog = new RetryMigrationDialog(
|
const retryMigrationDialog = new RetryMigrationDialog(
|
||||||
this._context,
|
this._context,
|
||||||
await MigrationLocalStorage.getMigrationServiceContext(),
|
await MigrationLocalStorage.getMigrationServiceContext(),
|
||||||
migration!,
|
migration,
|
||||||
this._onServiceContextChanged);
|
this._onServiceContextChanged);
|
||||||
await retryMigrationDialog.openDialog();
|
await retryMigrationDialog.openDialog();
|
||||||
}
|
}
|
||||||
@@ -418,11 +465,16 @@ export class DashboardWidget {
|
|||||||
private async _getMigrationById(migrationId: string, migrationOperationId: string): Promise<DatabaseMigration | undefined> {
|
private async _getMigrationById(migrationId: string, migrationOperationId: string): Promise<DatabaseMigration | undefined> {
|
||||||
const context = await MigrationLocalStorage.getMigrationServiceContext();
|
const context = await MigrationLocalStorage.getMigrationServiceContext();
|
||||||
if (context.azureAccount && context.subscription) {
|
if (context.azureAccount && context.subscription) {
|
||||||
return getMigrationDetails(
|
try {
|
||||||
context.azureAccount,
|
const migration = getMigrationDetails(
|
||||||
context.subscription,
|
context.azureAccount,
|
||||||
migrationId,
|
context.subscription,
|
||||||
migrationOperationId);
|
migrationId,
|
||||||
|
migrationOperationId);
|
||||||
|
return migration;
|
||||||
|
} catch (error) {
|
||||||
|
logError(TelemetryViews.MigrationsTab, "_getMigrationById", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import * as azdata from 'azdata';
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as azurecore from 'azurecore';
|
import * as azurecore from 'azurecore';
|
||||||
import { DatabaseMigration, SqlMigrationService, getSubscriptions, getServiceMigrations } from '../api/azure';
|
import { DatabaseMigration, SqlMigrationService, getSubscriptions, getServiceMigrations } from '../api/azure';
|
||||||
import { deepClone } from '../api/utils';
|
import { deepClone, isAccountTokenStale } from '../api/utils';
|
||||||
import * as loc from '../constants/strings';
|
import * as loc from '../constants/strings';
|
||||||
import { ServiceContextChangeEvent } from '../dashboard/tabBase';
|
import { ServiceContextChangeEvent } from '../dashboard/tabBase';
|
||||||
import { getSourceConnectionProfile } from '../api/sqlUtils';
|
import { getSourceConnectionProfile } from '../api/sqlUtils';
|
||||||
@@ -38,9 +38,9 @@ export class MigrationLocalStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async refreshMigrationAzureAccount(serviceContext: MigrationServiceContext, migration: DatabaseMigration, serviceContextChangedEvent: vscode.EventEmitter<ServiceContextChangeEvent>): Promise<void> {
|
public static async refreshMigrationAzureAccount(serviceContext: MigrationServiceContext, migration: DatabaseMigration, serviceContextChangedEvent: vscode.EventEmitter<ServiceContextChangeEvent>): Promise<void> {
|
||||||
if (serviceContext.azureAccount?.isStale) {
|
if (isAccountTokenStale(serviceContext.azureAccount)) {
|
||||||
const accounts = await azdata.accounts.getAllAccounts();
|
const accounts = await azdata.accounts.getAllAccounts();
|
||||||
const account = accounts.find(a => !a.isStale && a.key.accountId === serviceContext.azureAccount?.key.accountId);
|
const account = accounts.find(a => !isAccountTokenStale(a) && a.key.accountId === serviceContext.azureAccount?.key.accountId);
|
||||||
if (account) {
|
if (account) {
|
||||||
const subscriptions = await getSubscriptions(account);
|
const subscriptions = await getSubscriptions(account);
|
||||||
const subscription = subscriptions.find(s => s.id === serviceContext.subscription?.id);
|
const subscription = subscriptions.find(s => s.id === serviceContext.subscription?.id);
|
||||||
@@ -55,7 +55,7 @@ export class MigrationLocalStorage {
|
|||||||
|
|
||||||
export function isServiceContextValid(serviceContext: MigrationServiceContext): boolean {
|
export function isServiceContextValid(serviceContext: MigrationServiceContext): boolean {
|
||||||
return (
|
return (
|
||||||
serviceContext.azureAccount?.isStale === false &&
|
!isAccountTokenStale(serviceContext.azureAccount) &&
|
||||||
serviceContext.location?.id !== undefined &&
|
serviceContext.location?.id !== undefined &&
|
||||||
serviceContext.migrationService?.id !== undefined &&
|
serviceContext.migrationService?.id !== undefined &&
|
||||||
serviceContext.resourceGroup?.id !== undefined &&
|
serviceContext.resourceGroup?.id !== undefined &&
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export enum TelemetryViews {
|
|||||||
MigrationStatusDialog = 'MigrationStatusDialog',
|
MigrationStatusDialog = 'MigrationStatusDialog',
|
||||||
DashboardTab = 'DashboardTab',
|
DashboardTab = 'DashboardTab',
|
||||||
MigrationsTab = 'MigrationsTab',
|
MigrationsTab = 'MigrationsTab',
|
||||||
|
MigrationDetailsTab = 'MigrationDetailsTab',
|
||||||
MigrationWizardAccountSelectionPage = 'MigrationWizardAccountSelectionPage',
|
MigrationWizardAccountSelectionPage = 'MigrationWizardAccountSelectionPage',
|
||||||
MigrationWizardSkuRecommendationPage = 'MigrationWizardSkuRecommendationPage',
|
MigrationWizardSkuRecommendationPage = 'MigrationWizardSkuRecommendationPage',
|
||||||
MigrationWizardTargetSelectionPage = 'MigrationWizardTargetSelectionPage',
|
MigrationWizardTargetSelectionPage = 'MigrationWizardTargetSelectionPage',
|
||||||
@@ -56,6 +57,7 @@ export enum TelemetryAction {
|
|||||||
StartMigration = 'StartMigration',
|
StartMigration = 'StartMigration',
|
||||||
CutoverMigration = 'CutoverMigration',
|
CutoverMigration = 'CutoverMigration',
|
||||||
CancelMigration = 'CancelMigration',
|
CancelMigration = 'CancelMigration',
|
||||||
|
DeleteMigration = 'DeleteMigration',
|
||||||
MigrationStatus = 'MigrationStatus',
|
MigrationStatus = 'MigrationStatus',
|
||||||
PageButtonClick = 'PageButtonClick',
|
PageButtonClick = 'PageButtonClick',
|
||||||
Prev = 'prev',
|
Prev = 'prev',
|
||||||
|
|||||||
@@ -877,7 +877,8 @@ export class LoginMigrationTargetSelectionPage extends MigrationWizardPage {
|
|||||||
private async populateTenantsDropdown(): Promise<void> {
|
private async populateTenantsDropdown(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
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 (!utils.isAccountTokenStale(this.migrationStateModel._azureAccount) &&
|
||||||
|
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 = utils.getAzureTenantsDropdownValues(this.migrationStateModel._accountTenants);
|
this._accountTenantDropdown.values = utils.getAzureTenantsDropdownValues(this.migrationStateModel._accountTenants);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -886,7 +886,7 @@ export class TargetSelectionPage extends MigrationWizardPage {
|
|||||||
private async populateTenantsDropdown(): Promise<void> {
|
private async populateTenantsDropdown(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
this._accountTenantDropdown.loading = true;
|
this._accountTenantDropdown.loading = true;
|
||||||
if (this.migrationStateModel._azureAccount?.isStale === false &&
|
if (!utils.isAccountTokenStale(this.migrationStateModel._azureAccount) &&
|
||||||
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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user