Add callout dialog from error count to detailed error message on migration status dialog (#16850)

This commit is contained in:
goyal-anjali
2021-10-07 22:43:31 +05:30
committed by GitHub
parent e170a9b4a9
commit 0dd544aff4
3 changed files with 77 additions and 11 deletions

View File

@@ -223,6 +223,8 @@ export const NAME_OF_NEW_RESOURCE_GROUP = localize('sql.migration.name.of.new.rg
export const DATA_UPLOADED_INFO = localize('sql.migration.data.uploaded.info', "Comparison of the actual amount of data read from the source and the actual amount of data uploaded to the target.");
export const COPY_THROUGHPUT_INFO = localize('sql.migration.copy.throughput.info', "Data movement throughput achieved during the migration of your database backups to Azure. This is the rate of data transfer, calculated by data read divided by duration of backups migration to Azure.");
// common strings
export const WARNING = localize('sql.migration.warning', "Warning");
export const ERROR = localize('sql.migration.error', "Error");
export const LEARN_MORE = localize('sql.migration.learn.more', "Learn more");
export const LEARN_MORE_ABOUT_PRE_REQS = localize('sql.migration.learn.more.pre.reqs', "Learn more about things you need before starting a migration.");
export const SUBSCRIPTION = localize('sql.migration.subscription', "Subscription");

View File

@@ -7,6 +7,7 @@ import { getMigrationStatus, DatabaseMigration, startMigrationCutover, stopMigra
import { BackupFileInfoStatus, MigrationContext } from '../../models/migrationLocalStorage';
import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../../telemtery';
import * as constants from '../../constants/strings';
import { EOL } from 'os';
import { getMigrationTargetType, getMigrationMode } from '../../constants/helper';
export class MigrationCutoverDialogModel {
@@ -75,6 +76,17 @@ export class MigrationCutoverDialogModel {
return undefined!;
}
public async fetchErrors(): Promise<string> {
const errors = [];
await this.fetchStatus();
errors.push(this.migrationOpStatus.error?.message);
errors.push(this._migration.asyncOperationResult?.error?.message);
errors.push(this.migrationStatus.properties.migrationFailureError?.message);
return errors
.filter((e, i, arr) => e !== undefined && i === arr.indexOf(e))
.join(EOL);
}
public async cancelMigration(): Promise<void> {
try {
this.CancelMigrationError = undefined;

View File

@@ -436,12 +436,45 @@ export class MigrationStatusDialog {
warningCount++;
}
return this._getStatusControl(migrationStatus, warningCount);
return this._getStatusControl(migrationStatus, warningCount, migration);
}
private _getStatusControl(status: string, count: number): azdata.FlexContainer {
public openCalloutDialog(dialogHeading: string, dialogName?: string, calloutMessageText?: string): void {
const dialog = azdata.window.createModelViewDialog(dialogHeading, dialogName, 288, 'callout', 'left', true, false,
{
xPos: 0,
yPos: 0,
width: 20,
height: 20
});
const tab: azdata.window.DialogTab = azdata.window.createTab('');
tab.registerContent(async view => {
const warningContentContainer = view.modelBuilder.divContainer().component();
const messageTextComponent = view.modelBuilder.text().withProps({
value: calloutMessageText,
CSSStyles: {
'font-size': '12px',
'line-height': '16px',
'margin': '0 0 12px 0',
'display': '-webkit-box',
'-webkit-box-orient': 'vertical',
'-webkit-line-clamp': '5',
'overflow': 'hidden'
}
}).component();
warningContentContainer.addItem(messageTextComponent);
await view.initializeModel(warningContentContainer);
});
dialog.content = [tab];
azdata.window.openDialog(dialog);
}
private _getStatusControl(status: string, count: number, migration: MigrationContext): azdata.DivContainer {
const control = this._view.modelBuilder
.flexContainer()
.divContainer()
.withItems([
// migration status icon
this._view.modelBuilder.image()
@@ -465,23 +498,42 @@ export class MigrationStatusDialog {
.component();
if (count > 0) {
control.addItems([
// migration warning / error image
this._view.modelBuilder.image().withProps({
const migrationWarningImage = this._view.modelBuilder.image()
.withProps({
iconPath: this._statusInfoMap(status),
iconHeight: statusImageSize,
iconWidth: statusImageSize,
height: statusImageSize,
width: statusImageSize,
CSSStyles: imageCellStyles
}).component(),
// migration warning / error counts
this._view.modelBuilder.text().withProps({
value: loc.STATUS_WARNING_COUNT(status, count),
}).component();
const migrationWarningCount = this._view.modelBuilder.hyperlink()
.withProps({
label: loc.STATUS_WARNING_COUNT(status, count) ?? '',
ariaLabel: loc.ERROR,
url: '',
height: statusImageSize,
CSSStyles: statusCellStyles,
}).component()
}).component();
control.addItems([
migrationWarningImage,
migrationWarningCount
]);
this._disposables.push(migrationWarningCount.onDidClick(async () => {
const cutoverDialogModel = new MigrationCutoverDialogModel(migration!);
const errors = await cutoverDialogModel.fetchErrors();
this.openCalloutDialog(
status === MigrationStatus.InProgress
|| status === MigrationStatus.Completing
? loc.WARNING
: loc.ERROR,
'input-table-row-dialog',
errors
);
}));
}
return control;