mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-01 09:35:41 -05:00
Surfacing migration errors in dashboard (#14956)
* vbumping migration * Adding 2 new icons cancel and warning * Fixed help link display text in assessments * Adding summary page redesign and resource name validations * Made headings bold * Fixed sku recommendation page styling Added check item for assessment * Validating account dropdown after token refresh * Renamed cutover to mode * cutover to mode renaming changes. * Converting to details api for more warnings * Added target database name and fixed cancel icon * Surfacing warning info in dashboard. * Consolidated fetch migrations logic Localilzed some strings Surface migration errors in dashboard and status page Table redesign in status dialog Fixed a major bug that happens when multiple dashboards are opened due to class variable sharing * removing console count * Fixing regex for SQL MI database names * Allowing spaces in regex
This commit is contained in:
@@ -103,6 +103,7 @@ export class AccountsSelectionPage extends MigrationWizardPage {
|
||||
this.wizard.message = {
|
||||
text: ''
|
||||
};
|
||||
this._azureAccountsDropdown.validate();
|
||||
});
|
||||
|
||||
const flexContainer = view.modelBuilder.flexContainer()
|
||||
|
||||
@@ -271,7 +271,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
}).withValidation((component) => {
|
||||
if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
if (component.value) {
|
||||
if (!/(?<=\\\\)[^\\]*/.test(component.value)) {
|
||||
if (!/^[\\\/]{2,}[^\\\/]+[\\\/]+[^\\\/]+/.test(component.value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -304,7 +304,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
.withValidation((component) => {
|
||||
if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
if (component.value) {
|
||||
if (!/(?<=\\).*$/.test(component.value)) {
|
||||
if (!/^[A-Za-z0-9\\\._-]{7,}$/.test(component.value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -512,10 +512,14 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
c.validationErrorMessage = constants.DATABASE_ALREADY_EXISTS_MI(this.migrationStateModel._targetServerInstance.name);
|
||||
return false;
|
||||
}
|
||||
if (c.value!.length < 1 || c.value!.length > 128 || !/[^<>*%&:\\\/?]/.test(c.value!)) {
|
||||
c.validationErrorMessage = constants.INVALID_TARGET_NAME_ERROR;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
targetNameNetworkInputBox.onTextChanged((value) => {
|
||||
this.migrationStateModel._targetDatabaseNames[index] = value;
|
||||
this.migrationStateModel._targetDatabaseNames[index] = value.trim();
|
||||
});
|
||||
this._targetDatabaseNames.push(targetNameNetworkInputBox);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationCutover, MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
|
||||
import { MigrationMode, MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../constants/strings';
|
||||
|
||||
export class MigrationModePage extends MigrationWizardPage {
|
||||
@@ -57,11 +57,11 @@ export class MigrationModePage extends MigrationWizardPage {
|
||||
}
|
||||
}).component();
|
||||
|
||||
this.migrationStateModel._databaseBackup.migrationCutover = MigrationCutover.ONLINE;
|
||||
this.migrationStateModel._databaseBackup.migrationMode = MigrationMode.ONLINE;
|
||||
|
||||
onlineButton.onDidChangeCheckedState((e) => {
|
||||
if (e) {
|
||||
this.migrationStateModel._databaseBackup.migrationCutover = MigrationCutover.ONLINE;
|
||||
this.migrationStateModel._databaseBackup.migrationMode = MigrationMode.ONLINE;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ export class SKURecommendationPage extends MigrationWizardPage {
|
||||
|
||||
private _view!: azdata.ModelView;
|
||||
private _igComponent!: azdata.TextComponent;
|
||||
private _assessmentStatusIcon!: azdata.ImageComponent;
|
||||
private _detailsComponent!: azdata.TextComponent;
|
||||
private _chooseTargetComponent!: azdata.DivContainer;
|
||||
private _azureSubscriptionText!: azdata.TextComponent;
|
||||
@@ -63,7 +64,31 @@ export class SKURecommendationPage extends MigrationWizardPage {
|
||||
protected async registerContent(view: azdata.ModelView) {
|
||||
this._view = view;
|
||||
this._igComponent = this.createStatusComponent(view); // The first component giving basic information
|
||||
this._assessmentStatusIcon = this._view.modelBuilder.image().withProps({
|
||||
iconPath: IconPathHelper.completedMigration,
|
||||
iconHeight: 17,
|
||||
iconWidth: 17,
|
||||
width: 17,
|
||||
height: 20
|
||||
}).component();
|
||||
const igContainer = this._view.modelBuilder.flexContainer().component();
|
||||
igContainer.addItem(this._assessmentStatusIcon, {
|
||||
flex: '0 0 auto'
|
||||
});
|
||||
igContainer.addItem(this._igComponent, {
|
||||
flex: '0 0 auto'
|
||||
});
|
||||
|
||||
this._detailsComponent = this.createDetailsComponent(view); // The details of what can be moved
|
||||
|
||||
const statusContainer = this._view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).withItems(
|
||||
[
|
||||
igContainer,
|
||||
this._detailsComponent
|
||||
]
|
||||
).component();
|
||||
this._chooseTargetComponent = await this.createChooseTargetComponent(view);
|
||||
this._azureSubscriptionText = this.createAzureSubscriptionText(view);
|
||||
|
||||
@@ -164,11 +189,7 @@ export class SKURecommendationPage extends MigrationWizardPage {
|
||||
[
|
||||
{
|
||||
title: '',
|
||||
component: this._igComponent
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
component: this._detailsComponent
|
||||
component: statusContainer
|
||||
},
|
||||
{
|
||||
title: constants.SKU_RECOMMENDATION_CHOOSE_A_TARGET,
|
||||
@@ -212,14 +233,20 @@ export class SKURecommendationPage extends MigrationWizardPage {
|
||||
private createStatusComponent(view: azdata.ModelView): azdata.TextComponent {
|
||||
const component = view.modelBuilder.text().withProps({
|
||||
CSSStyles: {
|
||||
'font-size': '14px'
|
||||
'font-size': '14px',
|
||||
'margin': '0 0 0 8px',
|
||||
'line-height': '20px'
|
||||
}
|
||||
}).component();
|
||||
return component;
|
||||
}
|
||||
|
||||
private createDetailsComponent(view: azdata.ModelView): azdata.TextComponent {
|
||||
const component = view.modelBuilder.text().component();
|
||||
const component = view.modelBuilder.text().withProps({
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).component();
|
||||
return component;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationStateModel, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
|
||||
import { MigrationMode, MigrationStateModel, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../constants/strings';
|
||||
import { createHeadingTextComponent, createInformationRow } from './wizardController';
|
||||
|
||||
@@ -36,19 +36,32 @@ export class SummaryPage extends MigrationWizardPage {
|
||||
public async onPageEnter(): Promise<void> {
|
||||
this._flexContainer.addItems(
|
||||
[
|
||||
createHeadingTextComponent(this._view, constants.AZURE_ACCOUNT_LINKED),
|
||||
createHeadingTextComponent(this._view, this.migrationStateModel._azureAccount.displayInfo.displayName),
|
||||
createHeadingTextComponent(this._view, constants.MIGRATION_TARGET),
|
||||
createInformationRow(this._view, constants.TYPE, (this.migrationStateModel._targetServerInstance.type === 'microsoft.compute/virtualmachines') ? constants.SUMMARY_VM_TYPE : constants.SUMMARY_MI_TYPE),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name),
|
||||
createInformationRow(this._view, constants.SUMMARY_MI_TYPE, this.migrationStateModel._targetServerInstance.name),
|
||||
createInformationRow(this._view, constants.SUMMARY_DATABASE_COUNT_LABEL, this.migrationStateModel._migrationDbs.length.toString()),
|
||||
createHeadingTextComponent(this._view, constants.DATABASE_BACKUP_PAGE_TITLE),
|
||||
this.createNetworkContainerRows(),
|
||||
createHeadingTextComponent(this._view, constants.IR_PAGE_TITLE),
|
||||
createInformationRow(this._view, constants.IR_PAGE_TITLE, this.migrationStateModel._sqlMigrationService?.name!),
|
||||
createInformationRow(this._view, constants.SUMMARY_IR_NODE, this.migrationStateModel._nodeNames.join(', ')),
|
||||
createHeadingTextComponent(this._view, constants.ACCOUNTS_SELECTION_PAGE_TITLE),
|
||||
createInformationRow(this._view, constants.ACCOUNTS_SELECTION_PAGE_TITLE, this.migrationStateModel._azureAccount.displayInfo.displayName),
|
||||
|
||||
createHeadingTextComponent(this._view, constants.SOURCE_DATABASES),
|
||||
createInformationRow(this._view, constants.SUMMARY_DATABASE_COUNT_LABEL, this.migrationStateModel._migrationDbs.length.toString()),
|
||||
|
||||
createHeadingTextComponent(this._view, constants.SKU_RECOMMENDATION_PAGE_TITLE),
|
||||
createInformationRow(this._view, constants.SKU_RECOMMENDATION_PAGE_TITLE, (this.migrationStateModel._targetServerInstance.type === 'microsoft.compute/virtualmachines') ? constants.SUMMARY_VM_TYPE : constants.SUMMARY_MI_TYPE),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name),
|
||||
createInformationRow(this._view, constants.LOCATION, await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.location)),
|
||||
createInformationRow(this._view, constants.RESOURCE_GROUP, await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.resourceGroup!)),
|
||||
createInformationRow(this._view, (this.migrationStateModel._targetServerInstance.type === 'microsoft.compute/virtualmachines') ? constants.SUMMARY_VM_TYPE : constants.SUMMARY_MI_TYPE, await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.name!)),
|
||||
|
||||
createHeadingTextComponent(this._view, constants.DATABASE_BACKUP_MIGRATION_MODE_LABEL),
|
||||
createInformationRow(this._view, constants.MODE, this.migrationStateModel._databaseBackup.migrationMode === MigrationMode.ONLINE ? constants.DATABASE_BACKUP_MIGRATION_MODE_ONLINE_LABEL : constants.DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_LABEL),
|
||||
|
||||
createHeadingTextComponent(this._view, constants.DATABASE_BACKUP_PAGE_TITLE),
|
||||
await this.createNetworkContainerRows(),
|
||||
|
||||
createHeadingTextComponent(this._view, constants.IR_PAGE_TITLE),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name),
|
||||
createInformationRow(this._view, constants.LOCATION, this.migrationStateModel._sqlMigrationService.location),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._sqlMigrationService.properties.resourceGroup),
|
||||
createInformationRow(this._view, constants.IR_PAGE_TITLE, this.migrationStateModel._targetSubscription.name),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._sqlMigrationService.name),
|
||||
createInformationRow(this._view, constants.SHIR, this.migrationStateModel._nodeNames[0]),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -63,7 +76,7 @@ export class SummaryPage extends MigrationWizardPage {
|
||||
protected async handleStateChange(e: StateChangeEvent): Promise<void> {
|
||||
}
|
||||
|
||||
private createNetworkContainerRows(): azdata.FlexContainer {
|
||||
private async createNetworkContainerRows(): Promise<azdata.FlexContainer> {
|
||||
const flexContainer = this._view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
@@ -71,11 +84,14 @@ export class SummaryPage extends MigrationWizardPage {
|
||||
case NetworkContainerType.NETWORK_SHARE:
|
||||
flexContainer.addItems(
|
||||
[
|
||||
createInformationRow(this._view, constants.TYPE, constants.NETWORK_SHARE),
|
||||
createInformationRow(this._view, constants.DATABASE_BACKUP_NETWORK_SHARE_LOCATION_LABEL, this.migrationStateModel._databaseBackup.networkShareLocation),
|
||||
createInformationRow(this._view, constants.BACKUP_LOCATION, constants.NETWORK_SHARE),
|
||||
createInformationRow(this._view, constants.NETWORK_SHARE, this.migrationStateModel._databaseBackup.networkShareLocation),
|
||||
createInformationRow(this._view, constants.USER_ACCOUNT, this.migrationStateModel._databaseBackup.windowsUser),
|
||||
createInformationRow(this._view, constants.SUMMARY_AZURE_STORAGE_SUBSCRIPTION, this.migrationStateModel._databaseBackup.subscription.name),
|
||||
createInformationRow(this._view, constants.SUMMARY_AZURE_STORAGE, this.migrationStateModel._databaseBackup.storageAccount.name),
|
||||
createHeadingTextComponent(this._view, constants.AZURE_STORAGE_ACCOUNT_TO_UPLOAD_BACKUPS),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._databaseBackup.subscription.name),
|
||||
createInformationRow(this._view, constants.LOCATION, this.migrationStateModel._databaseBackup.storageAccount.location),
|
||||
createInformationRow(this._view, constants.RESOURCE_GROUP, this.migrationStateModel._databaseBackup.storageAccount.resourceGroup!),
|
||||
createInformationRow(this._view, constants.STORAGE_ACCOUNT, this.migrationStateModel._databaseBackup.storageAccount.name!),
|
||||
createHeadingTextComponent(this._view, 'Target Databases:')
|
||||
]
|
||||
);
|
||||
|
||||
@@ -110,7 +110,7 @@ export function createHeadingTextComponent(view: azdata.ModelView, value: string
|
||||
const component = createTextCompononent(view, value);
|
||||
component.updateCssStyles({
|
||||
'font-size': '13px',
|
||||
'font-weight': 'bold'
|
||||
'font-weight': 'bold',
|
||||
});
|
||||
return component;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user