mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-27 01:25:36 -05:00
Renaming controller to migration service and other bug fixes/ validations. (#14751)
* - Added coming soon message for learn more. - Potential fix for learn more message * Renaming of controller to sqlMigrationService * Surfacing some errors -Azure account is stale error -Migration Service creation error. * Adding refresh azure token validation. * Fixing some errors pointed during PR -Fixing property names -Fixing count * Fixing migration status - Adding special error handling for resource not found error - Deleting unfound migrations from local cache - Using prefetched migration status for view all Misc fixes: - Using SQL server version name instead of number - Fixing Icons on sku recommendation page - Fixing table column width in cutover dialog - Adding spinner button to refresh. * Fixing all strings in migration service page and dialog * fixed a string error in create service dialog
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { createMigrationController, getMigrationControllerRegions, getMigrationController, getResourceGroups, getMigrationControllerAuthKeys, getMigrationControllerMonitoringData } from '../../api/azure';
|
||||
import { createSqlMigrationService, getSqlMigrationServiceRegions, getSqlMigrationService, getResourceGroups, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlMigrationService } from '../../api/azure';
|
||||
import { MigrationStateModel } from '../../models/stateMachine';
|
||||
import * as constants from '../../constants/strings';
|
||||
import * as os from 'os';
|
||||
@@ -13,16 +13,16 @@ import { azureResource } from 'azureResource';
|
||||
import { IntergrationRuntimePage } from '../../wizard/integrationRuntimePage';
|
||||
import { IconPathHelper } from '../../constants/iconPathHelper';
|
||||
|
||||
export class CreateMigrationControllerDialog {
|
||||
export class CreateSqlMigrationServiceDialog {
|
||||
|
||||
private migrationControllerSubscriptionDropdown!: azdata.DropDownComponent;
|
||||
private migrationControllerResourceGroupDropdown!: azdata.DropDownComponent;
|
||||
private migrationControllerRegionDropdown!: azdata.DropDownComponent;
|
||||
private migrationControllerNameText!: azdata.InputBoxComponent;
|
||||
private migrationServiceSubscriptionDropdown!: azdata.DropDownComponent;
|
||||
private migrationServiceResourceGroupDropdown!: azdata.DropDownComponent;
|
||||
private migrationServiceRegionDropdown!: azdata.DropDownComponent;
|
||||
private migrationServiceNameText!: azdata.InputBoxComponent;
|
||||
private _formSubmitButton!: azdata.ButtonComponent;
|
||||
|
||||
private _statusLoadingComponent!: azdata.LoadingComponent;
|
||||
private migrationControllerAuthKeyTable!: azdata.DeclarativeTableComponent;
|
||||
private migrationServiceAuthKeyTable!: azdata.DeclarativeTableComponent;
|
||||
private _connectionStatus!: azdata.InfoBoxComponent;
|
||||
private _copyKey1Button!: azdata.ButtonComponent;
|
||||
private _copyKey2Button!: azdata.ButtonComponent;
|
||||
@@ -33,8 +33,11 @@ export class CreateMigrationControllerDialog {
|
||||
private _dialogObject!: azdata.window.Dialog;
|
||||
private _view!: azdata.ModelView;
|
||||
|
||||
private createdMigrationService!: SqlMigrationService;
|
||||
private createdMigrationServiceNodeNames!: string[];
|
||||
|
||||
constructor(private migrationStateModel: MigrationStateModel, private irPage: IntergrationRuntimePage) {
|
||||
this._dialogObject = azdata.window.createModelViewDialog(constants.IR_PAGE_TITLE, 'MigrationControllerDialog', 'medium');
|
||||
this._dialogObject = azdata.window.createModelViewDialog(constants.CREATE_MIGRATION_SERVICE_TITLE, 'MigrationServiceDialog', 'medium');
|
||||
}
|
||||
|
||||
initialize() {
|
||||
@@ -51,15 +54,18 @@ export class CreateMigrationControllerDialog {
|
||||
}).component();
|
||||
|
||||
this._formSubmitButton.onDidClick(async (e) => {
|
||||
this._dialogObject.message = {
|
||||
text: ''
|
||||
};
|
||||
this._statusLoadingComponent.loading = true;
|
||||
this._formSubmitButton.enabled = false;
|
||||
|
||||
const subscription = this.migrationStateModel._targetSubscription;
|
||||
const resourceGroup = (this.migrationControllerResourceGroupDropdown.value as azdata.CategoryValue).name;
|
||||
const region = (this.migrationControllerRegionDropdown.value as azdata.CategoryValue).name;
|
||||
const controllerName = this.migrationControllerNameText.value;
|
||||
const resourceGroup = (this.migrationServiceResourceGroupDropdown.value as azdata.CategoryValue).name;
|
||||
const region = (this.migrationServiceRegionDropdown.value as azdata.CategoryValue).name;
|
||||
const serviceName = this.migrationServiceNameText.value;
|
||||
|
||||
const formValidationErrors = this.validateCreateControllerForm(subscription, resourceGroup, region, controllerName);
|
||||
const formValidationErrors = this.validateCreateServiceForm(subscription, resourceGroup, region, serviceName);
|
||||
|
||||
if (formValidationErrors.length > 0) {
|
||||
this.setDialogMessage(formValidationErrors);
|
||||
@@ -69,9 +75,9 @@ export class CreateMigrationControllerDialog {
|
||||
}
|
||||
|
||||
try {
|
||||
const createdController = await createMigrationController(this.migrationStateModel._azureAccount, subscription, resourceGroup, region, controllerName!);
|
||||
if (createdController.error) {
|
||||
this.setDialogMessage(`${createdController.error.code} : ${createdController.error.message}`);
|
||||
this.createdMigrationService = await createSqlMigrationService(this.migrationStateModel._azureAccount, subscription, resourceGroup, region, serviceName!);
|
||||
if (this.createdMigrationService.error) {
|
||||
this.setDialogMessage(`${this.createdMigrationService.error.code} : ${this.createdMigrationService.error.message}`);
|
||||
this._statusLoadingComponent.loading = false;
|
||||
this._formSubmitButton.enabled = true;
|
||||
return;
|
||||
@@ -79,13 +85,13 @@ export class CreateMigrationControllerDialog {
|
||||
this._dialogObject.message = {
|
||||
text: ''
|
||||
};
|
||||
this.migrationStateModel._migrationController = createdController;
|
||||
await this.refreshAuthTable();
|
||||
await this.refreshStatus();
|
||||
this._setupContainer.display = 'inline';
|
||||
this._statusLoadingComponent.loading = false;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.setDialogMessage(e.message);
|
||||
this._statusLoadingComponent.loading = false;
|
||||
this._formSubmitButton.enabled = true;
|
||||
return;
|
||||
@@ -93,16 +99,16 @@ export class CreateMigrationControllerDialog {
|
||||
});
|
||||
|
||||
this._statusLoadingComponent = view.modelBuilder.loadingComponent().withProps({
|
||||
loadingText: constants.CONTROLLER_DIALOG_CONTROLLER_CONTAINER_LOADING_HELP,
|
||||
loadingText: constants.LOADING_MIGRATION_SERVICES,
|
||||
loading: false
|
||||
}).component();
|
||||
|
||||
const creationStatusContainer = this.createControllerStatus();
|
||||
const creationStatusContainer = this.createServiceStatus();
|
||||
|
||||
const formBuilder = view.modelBuilder.formContainer().withFormItems(
|
||||
[
|
||||
{
|
||||
component: this.migrationControllerDropdownsContainer()
|
||||
component: this.migrationServiceDropdownContainer()
|
||||
},
|
||||
{
|
||||
component: this._formSubmitButton
|
||||
@@ -132,36 +138,30 @@ export class CreateMigrationControllerDialog {
|
||||
this._dialogObject.cancelButton.onClick((e) => {
|
||||
});
|
||||
this._dialogObject.okButton.onClick((e) => {
|
||||
this.irPage.populateMigrationController();
|
||||
this.irPage.populateMigrationService(this.createdMigrationService, this.createdMigrationServiceNodeNames);
|
||||
});
|
||||
}
|
||||
|
||||
private migrationControllerDropdownsContainer(): azdata.FlexContainer {
|
||||
private migrationServiceDropdownContainer(): azdata.FlexContainer {
|
||||
const dialogDescription = this._view.modelBuilder.text().withProps({
|
||||
value: constants.IR_PAGE_DESCRIPTION,
|
||||
links: [
|
||||
{
|
||||
text: constants.LEARN_MORE,
|
||||
url: 'https://www.microsoft.com' // TODO: add a proper link to the docs.
|
||||
}
|
||||
]
|
||||
value: constants.MIGRATION_SERVICE_DIALOG_DESCRIPTION
|
||||
}).component();
|
||||
|
||||
const formHeading = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_DIALOG_CREATE_CONTROLLER_FORM_HEADING
|
||||
value: constants.CREATE_SERVICE_FORM_HEADING
|
||||
}).component();
|
||||
|
||||
const subscriptionDropdownLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SUBSCRIPTION
|
||||
}).component();
|
||||
|
||||
this.migrationControllerSubscriptionDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
this.migrationServiceSubscriptionDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
required: true,
|
||||
enabled: false
|
||||
}).component();
|
||||
|
||||
this.migrationControllerSubscriptionDropdown.onValueChanged((e) => {
|
||||
if (this.migrationControllerSubscriptionDropdown.value) {
|
||||
this.migrationServiceSubscriptionDropdown.onValueChanged((e) => {
|
||||
if (this.migrationServiceSubscriptionDropdown.value) {
|
||||
this.populateResourceGroups();
|
||||
}
|
||||
});
|
||||
@@ -170,43 +170,43 @@ export class CreateMigrationControllerDialog {
|
||||
value: constants.RESOURCE_GROUP
|
||||
}).component();
|
||||
|
||||
this.migrationControllerResourceGroupDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
this.migrationServiceResourceGroupDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
required: true
|
||||
}).component();
|
||||
|
||||
const controllerNameLabel = this._view.modelBuilder.text().withProps({
|
||||
const migrationServiceNameLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.NAME
|
||||
}).component();
|
||||
|
||||
this.migrationControllerNameText = this._view.modelBuilder.inputBox().component();
|
||||
this.migrationServiceNameText = this._view.modelBuilder.inputBox().component();
|
||||
|
||||
const regionsDropdownLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.REGION
|
||||
}).component();
|
||||
|
||||
this.migrationControllerRegionDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
this.migrationServiceRegionDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
required: true,
|
||||
values: getMigrationControllerRegions()
|
||||
values: getSqlMigrationServiceRegions()
|
||||
}).component();
|
||||
|
||||
const flexContainer = this._view.modelBuilder.flexContainer().withItems([
|
||||
dialogDescription,
|
||||
formHeading,
|
||||
subscriptionDropdownLabel,
|
||||
this.migrationControllerSubscriptionDropdown,
|
||||
this.migrationServiceSubscriptionDropdown,
|
||||
resourceGroupDropdownLabel,
|
||||
this.migrationControllerResourceGroupDropdown,
|
||||
controllerNameLabel,
|
||||
this.migrationControllerNameText,
|
||||
this.migrationServiceResourceGroupDropdown,
|
||||
migrationServiceNameLabel,
|
||||
this.migrationServiceNameText,
|
||||
regionsDropdownLabel,
|
||||
this.migrationControllerRegionDropdown
|
||||
this.migrationServiceRegionDropdown
|
||||
]).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
return flexContainer;
|
||||
}
|
||||
|
||||
private validateCreateControllerForm(subscription: azureResource.AzureResourceSubscription, resourceGroup: string | undefined, region: string | undefined, controllerName: string | undefined): string {
|
||||
private validateCreateServiceForm(subscription: azureResource.AzureResourceSubscription, resourceGroup: string | undefined, region: string | undefined, migrationServiceName: string | undefined): string {
|
||||
const errors: string[] = [];
|
||||
if (!subscription) {
|
||||
errors.push(constants.INVALID_SUBSCRIPTION_ERROR);
|
||||
@@ -217,29 +217,29 @@ export class CreateMigrationControllerDialog {
|
||||
if (!region) {
|
||||
errors.push(constants.INVALID_REGION_ERROR);
|
||||
}
|
||||
if (!controllerName || controllerName.length === 0) {
|
||||
errors.push(constants.INVALID_CONTROLLER_NAME_ERROR);
|
||||
if (!migrationServiceName || migrationServiceName.length === 0) {
|
||||
errors.push(constants.INVALID_SERVICE_NAME_ERROR);
|
||||
}
|
||||
return errors.join(os.EOL);
|
||||
}
|
||||
|
||||
private async populateSubscriptions(): Promise<void> {
|
||||
this.migrationControllerSubscriptionDropdown.loading = true;
|
||||
this.migrationControllerResourceGroupDropdown.loading = true;
|
||||
this.migrationServiceSubscriptionDropdown.loading = true;
|
||||
this.migrationServiceResourceGroupDropdown.loading = true;
|
||||
|
||||
|
||||
this.migrationControllerSubscriptionDropdown.values = [
|
||||
this.migrationServiceSubscriptionDropdown.values = [
|
||||
{
|
||||
displayName: this.migrationStateModel._targetSubscription.name,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
this.migrationControllerSubscriptionDropdown.loading = false;
|
||||
this.migrationServiceSubscriptionDropdown.loading = false;
|
||||
this.populateResourceGroups();
|
||||
}
|
||||
|
||||
private async populateResourceGroups(): Promise<void> {
|
||||
this.migrationControllerResourceGroupDropdown.loading = true;
|
||||
this.migrationServiceResourceGroupDropdown.loading = true;
|
||||
let subscription = this.migrationStateModel._targetSubscription;
|
||||
const resourceGroups = await getResourceGroups(this.migrationStateModel._azureAccount, subscription);
|
||||
let resourceGroupDropdownValues: azdata.CategoryValue[] = [];
|
||||
@@ -258,39 +258,39 @@ export class CreateMigrationControllerDialog {
|
||||
}
|
||||
];
|
||||
}
|
||||
this.migrationControllerResourceGroupDropdown.values = resourceGroupDropdownValues;
|
||||
this.migrationControllerResourceGroupDropdown.loading = false;
|
||||
this.migrationServiceResourceGroupDropdown.values = resourceGroupDropdownValues;
|
||||
this.migrationServiceResourceGroupDropdown.loading = false;
|
||||
}
|
||||
|
||||
private createControllerStatus(): azdata.FlexContainer {
|
||||
private createServiceStatus(): azdata.FlexContainer {
|
||||
|
||||
const setupIRHeadingText = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_DIALOG_CONTROLLER_CONTAINER_HEADING,
|
||||
value: constants.SERVICE_CONTAINER_HEADING,
|
||||
CSSStyles: {
|
||||
'font-weight': 'bold'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const setupIRdescription = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_DIALOG_CONTROLLER_CONTAINER_DESCRIPTION,
|
||||
value: constants.SERVICE_CONTAINER_DESCRIPTION,
|
||||
}).component();
|
||||
|
||||
const irSetupStep1Text = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_STEP1,
|
||||
value: constants.SERVICE_STEP1,
|
||||
links: [
|
||||
{
|
||||
text: constants.CONTROLLER_STEP1_LINK,
|
||||
text: constants.SERVICE_STEP1_LINK,
|
||||
url: 'https://www.microsoft.com/download/details.aspx?id=39717'
|
||||
}
|
||||
]
|
||||
}).component();
|
||||
|
||||
const irSetupStep2Text = this._view.modelBuilder.text().withProps({
|
||||
value: constants.CONTROLLER_STEP2
|
||||
value: constants.SERVICE_STEP2
|
||||
}).component();
|
||||
|
||||
const irSetupStep3Text = this._view.modelBuilder.hyperlink().withProps({
|
||||
label: constants.CONTROLLER_STEP3,
|
||||
label: constants.SERVICE_STEP3,
|
||||
url: '',
|
||||
CSSStyles: {
|
||||
'margin-top': '10px',
|
||||
@@ -326,7 +326,7 @@ export class CreateMigrationControllerDialog {
|
||||
}).component();
|
||||
|
||||
|
||||
this.migrationControllerAuthKeyTable = this._view.modelBuilder.declarativeTable().withProps({
|
||||
this.migrationServiceAuthKeyTable = this._view.modelBuilder.declarativeTable().withProps({
|
||||
columns: [
|
||||
{
|
||||
displayName: constants.NAME,
|
||||
@@ -370,7 +370,7 @@ export class CreateMigrationControllerDialog {
|
||||
setupIRdescription,
|
||||
irSetupStep1Text,
|
||||
irSetupStep2Text,
|
||||
this.migrationControllerAuthKeyTable,
|
||||
this.migrationServiceAuthKeyTable,
|
||||
irSetupStep3Text,
|
||||
this._connectionStatus,
|
||||
refreshLoadingIndicator
|
||||
@@ -389,26 +389,26 @@ export class CreateMigrationControllerDialog {
|
||||
|
||||
private async refreshStatus(): Promise<void> {
|
||||
const subscription = this.migrationStateModel._targetSubscription;
|
||||
const resourceGroup = (this.migrationControllerResourceGroupDropdown.value as azdata.CategoryValue).name;
|
||||
const region = (this.migrationControllerRegionDropdown.value as azdata.CategoryValue).name;
|
||||
const controllerStatus = await getMigrationController(this.migrationStateModel._azureAccount, subscription, resourceGroup, region, this.migrationStateModel._migrationController!.name);
|
||||
const controllerMonitoringStatus = await getMigrationControllerMonitoringData(this.migrationStateModel._azureAccount, subscription, resourceGroup, region, this.migrationStateModel._migrationController!.name);
|
||||
this.migrationStateModel._nodeNames = controllerMonitoringStatus.nodes.map((node) => {
|
||||
const resourceGroup = (this.migrationServiceResourceGroupDropdown.value as azdata.CategoryValue).name;
|
||||
const region = (this.migrationServiceRegionDropdown.value as azdata.CategoryValue).name;
|
||||
const migrationServiceStatus = await getSqlMigrationService(this.migrationStateModel._azureAccount, subscription, resourceGroup, region, this.createdMigrationService!.name);
|
||||
const migrationServiceMonitoringStatus = await getSqlMigrationServiceMonitoringData(this.migrationStateModel._azureAccount, subscription, resourceGroup, region, this.createdMigrationService!.name);
|
||||
this.createdMigrationServiceNodeNames = migrationServiceMonitoringStatus.nodes.map((node) => {
|
||||
return node.nodeName;
|
||||
});
|
||||
if (controllerStatus) {
|
||||
const state = controllerStatus.properties.integrationRuntimeState;
|
||||
if (migrationServiceStatus) {
|
||||
const state = migrationServiceStatus.properties.integrationRuntimeState;
|
||||
|
||||
if (state === 'Online') {
|
||||
this._connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.CONTROLLER_READY(this.migrationStateModel._migrationController!.name, this.migrationStateModel._nodeNames.join(', ')),
|
||||
text: constants.SERVICE_READY(this.createdMigrationService!.name, this.createdMigrationServiceNodeNames.join(', ')),
|
||||
style: 'success'
|
||||
});
|
||||
this._dialogObject.okButton.enabled = true;
|
||||
} else {
|
||||
this._connectionStatus.text = constants.CONTROLLER_NOT_READY(this.migrationStateModel._migrationController!.name);
|
||||
this._connectionStatus.text = constants.SERVICE_NOT_READY(this.createdMigrationService!.name);
|
||||
this._connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.CONTROLLER_NOT_READY(this.migrationStateModel._migrationController!.name),
|
||||
text: constants.SERVICE_NOT_READY(this.createdMigrationService!.name),
|
||||
style: 'warning'
|
||||
});
|
||||
this._dialogObject.okButton.enabled = false;
|
||||
@@ -418,17 +418,17 @@ export class CreateMigrationControllerDialog {
|
||||
}
|
||||
private async refreshAuthTable(): Promise<void> {
|
||||
const subscription = this.migrationStateModel._targetSubscription;
|
||||
const resourceGroup = (this.migrationControllerResourceGroupDropdown.value as azdata.CategoryValue).name;
|
||||
const region = (this.migrationControllerRegionDropdown.value as azdata.CategoryValue).name;
|
||||
const keys = await getMigrationControllerAuthKeys(this.migrationStateModel._azureAccount, subscription, resourceGroup, region, this.migrationStateModel._migrationController!.name);
|
||||
const resourceGroup = (this.migrationServiceResourceGroupDropdown.value as azdata.CategoryValue).name;
|
||||
const region = (this.migrationServiceRegionDropdown.value as azdata.CategoryValue).name;
|
||||
const keys = await getSqlMigrationServiceAuthKeys(this.migrationStateModel._azureAccount, subscription, resourceGroup, region, this.createdMigrationService!.name);
|
||||
|
||||
this._copyKey1Button = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.copy
|
||||
}).component();
|
||||
|
||||
this._copyKey1Button.onDidClick((e) => {
|
||||
vscode.env.clipboard.writeText(<string>this.migrationControllerAuthKeyTable.dataValues![0][1].value);
|
||||
vscode.window.showInformationMessage(constants.CONTROLLER_KEY_COPIED_HELP);
|
||||
vscode.env.clipboard.writeText(<string>this.migrationServiceAuthKeyTable.dataValues![0][1].value);
|
||||
vscode.window.showInformationMessage(constants.SERVICE_KEY_COPIED_HELP);
|
||||
});
|
||||
|
||||
this._copyKey2Button = this._view.modelBuilder.button().withProps({
|
||||
@@ -436,8 +436,8 @@ export class CreateMigrationControllerDialog {
|
||||
}).component();
|
||||
|
||||
this._copyKey2Button.onDidClick((e) => {
|
||||
vscode.env.clipboard.writeText(<string>this.migrationControllerAuthKeyTable.dataValues![1][1].value);
|
||||
vscode.window.showInformationMessage(constants.CONTROLLER_KEY_COPIED_HELP);
|
||||
vscode.env.clipboard.writeText(<string>this.migrationServiceAuthKeyTable.dataValues![1][1].value);
|
||||
vscode.window.showInformationMessage(constants.SERVICE_KEY_COPIED_HELP);
|
||||
});
|
||||
|
||||
this._refreshKey1Button = this._view.modelBuilder.button().withProps({
|
||||
@@ -454,11 +454,11 @@ export class CreateMigrationControllerDialog {
|
||||
this._refreshKey2Button.onDidClick((e) => { //TODO: add refresh logic
|
||||
});
|
||||
|
||||
this.migrationControllerAuthKeyTable.updateProperties({
|
||||
this.migrationServiceAuthKeyTable.updateProperties({
|
||||
dataValues: [
|
||||
[
|
||||
{
|
||||
value: constants.CONTROLLER_KEY1_LABEL
|
||||
value: constants.SERVICE_KEY1_LABEL
|
||||
},
|
||||
{
|
||||
value: keys.authKey1
|
||||
@@ -472,7 +472,7 @@ export class CreateMigrationControllerDialog {
|
||||
],
|
||||
[
|
||||
{
|
||||
value: constants.CONTROLLER_KEY2_LABEL
|
||||
value: constants.SERVICE_KEY2_LABEL
|
||||
},
|
||||
{
|
||||
value: keys.authKey2
|
||||
@@ -8,15 +8,17 @@ import { IconPathHelper } from '../../constants/iconPathHelper';
|
||||
import { MigrationContext } from '../../models/migrationLocalStorage';
|
||||
import { MigrationCutoverDialogModel } from './migrationCutoverDialogModel';
|
||||
import * as loc from '../../constants/strings';
|
||||
import { getSqlServerName } from '../../api/utils';
|
||||
export class MigrationCutoverDialog {
|
||||
private _dialogObject!: azdata.window.Dialog;
|
||||
private _view!: azdata.ModelView;
|
||||
private _model: MigrationCutoverDialogModel;
|
||||
|
||||
private _databaseTitleName!: azdata.TextComponent;
|
||||
private _databaseCutoverButton!: azdata.ButtonComponent;
|
||||
private _refresh!: azdata.ButtonComponent;
|
||||
private _cancel!: azdata.ButtonComponent;
|
||||
private _cutoverButton!: azdata.ButtonComponent;
|
||||
private _refreshButton!: azdata.ButtonComponent;
|
||||
private _cancelButton!: azdata.ButtonComponent;
|
||||
private _refreshLoader!: azdata.LoadingComponent;
|
||||
|
||||
private _serverName!: azdata.TextComponent;
|
||||
private _serverVersion!: azdata.TextComponent;
|
||||
@@ -43,7 +45,7 @@ export class MigrationCutoverDialog {
|
||||
let tab = azdata.window.createTab('');
|
||||
tab.registerContent(async (view: azdata.ModelView) => {
|
||||
this._view = view;
|
||||
const sourceDetails = this.createInfoField(loc.SOURCE_VERSION, '');
|
||||
const sourceDetails = this.createInfoField(loc.SOURCE_SERVER, '');
|
||||
const sourceVersion = this.createInfoField(loc.SOURCE_VERSION, '');
|
||||
|
||||
this._serverName = sourceDetails.text;
|
||||
@@ -183,30 +185,30 @@ export class MigrationCutoverDialog {
|
||||
columns: [
|
||||
{
|
||||
value: loc.ACTIVE_BACKUP_FILES,
|
||||
width: 150,
|
||||
width: 280,
|
||||
type: azdata.ColumnType.text
|
||||
},
|
||||
{
|
||||
value: loc.TYPE,
|
||||
width: 100,
|
||||
width: 90,
|
||||
type: azdata.ColumnType.text
|
||||
},
|
||||
{
|
||||
value: loc.STATUS,
|
||||
width: 100,
|
||||
width: 60,
|
||||
type: azdata.ColumnType.text
|
||||
},
|
||||
{
|
||||
value: loc.BACKUP_START_TIME,
|
||||
width: 150,
|
||||
width: 130,
|
||||
type: azdata.ColumnType.text
|
||||
}, {
|
||||
value: loc.FIRST_LSN,
|
||||
width: 150,
|
||||
width: 120,
|
||||
type: azdata.ColumnType.text
|
||||
}, {
|
||||
value: loc.LAST_LSN,
|
||||
width: 150,
|
||||
width: 120,
|
||||
type: azdata.ColumnType.text
|
||||
}
|
||||
],
|
||||
@@ -235,11 +237,12 @@ export class MigrationCutoverDialog {
|
||||
}
|
||||
);
|
||||
const form = formBuilder.withLayout({ width: '100%' }).component();
|
||||
return view.initializeModel(form);
|
||||
return view.initializeModel(form).then((value) => {
|
||||
this.refreshStatus();
|
||||
});
|
||||
});
|
||||
this._dialogObject.content = [tab];
|
||||
azdata.window.openDialog(this._dialogObject);
|
||||
this.refreshStatus();
|
||||
}
|
||||
|
||||
|
||||
@@ -262,7 +265,7 @@ export class MigrationCutoverDialog {
|
||||
}
|
||||
});
|
||||
|
||||
this._databaseCutoverButton = this._view.modelBuilder.button().withProps({
|
||||
this._cutoverButton = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.cutover,
|
||||
iconHeight: '14px',
|
||||
iconWidth: '12px',
|
||||
@@ -272,7 +275,7 @@ export class MigrationCutoverDialog {
|
||||
enabled: false
|
||||
}).component();
|
||||
|
||||
this._databaseCutoverButton.onDidClick(async (e) => {
|
||||
this._cutoverButton.onDidClick(async (e) => {
|
||||
if (this._startCutover) {
|
||||
await this._model.startCutover();
|
||||
this.refreshStatus();
|
||||
@@ -284,14 +287,14 @@ export class MigrationCutoverDialog {
|
||||
}
|
||||
});
|
||||
|
||||
header.addItem(this._databaseCutoverButton, {
|
||||
header.addItem(this._cutoverButton, {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'width': '100px'
|
||||
}
|
||||
});
|
||||
|
||||
this._cancel = this._view.modelBuilder.button().withProps({
|
||||
this._cancelButton = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.discard,
|
||||
iconHeight: '16px',
|
||||
iconWidth: '16px',
|
||||
@@ -300,11 +303,11 @@ export class MigrationCutoverDialog {
|
||||
width: '130px'
|
||||
}).component();
|
||||
|
||||
this._cancel.onDidClick((e) => {
|
||||
this._cancelButton.onDidClick((e) => {
|
||||
this.cancelMigration();
|
||||
});
|
||||
|
||||
header.addItem(this._cancel, {
|
||||
header.addItem(this._cancelButton, {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'width': '130px'
|
||||
@@ -312,7 +315,7 @@ export class MigrationCutoverDialog {
|
||||
});
|
||||
|
||||
|
||||
this._refresh = this._view.modelBuilder.button().withProps({
|
||||
this._refreshButton = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.refresh,
|
||||
iconHeight: '16px',
|
||||
iconWidth: '16px',
|
||||
@@ -321,28 +324,39 @@ export class MigrationCutoverDialog {
|
||||
width: '100px'
|
||||
}).component();
|
||||
|
||||
this._refresh.onDidClick((e) => {
|
||||
this._refreshButton.onDidClick((e) => {
|
||||
this.refreshStatus();
|
||||
});
|
||||
|
||||
header.addItem(this._refresh, {
|
||||
header.addItem(this._refreshButton, {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'width': '100px'
|
||||
}
|
||||
});
|
||||
|
||||
this._refreshLoader = this._view.modelBuilder.loadingComponent().withProps({
|
||||
loading: false,
|
||||
height: '55px'
|
||||
}).component();
|
||||
|
||||
header.addItem(this._refreshLoader, {
|
||||
flex: '0'
|
||||
});
|
||||
return header;
|
||||
}
|
||||
|
||||
|
||||
private async refreshStatus(): Promise<void> {
|
||||
try {
|
||||
this._refreshLoader.loading = true;
|
||||
this._cutoverButton.enabled = false;
|
||||
this._cancelButton.enabled = false;
|
||||
await this._model.fetchStatus();
|
||||
const sqlServerInfo = await azdata.connection.getServerInfo(this._model._migration.sourceConnectionProfile.connectionId);
|
||||
const sqlServerName = this._model._migration.sourceConnectionProfile.serverName;
|
||||
const sqlServerVersion = sqlServerInfo.serverVersion;
|
||||
const sqlServerEdition = sqlServerInfo.serverEdition;
|
||||
const versionName = getSqlServerName(sqlServerInfo.serverMajorVersion!);
|
||||
const sqlServerVersion = versionName ? versionName : sqlServerInfo.serverVersion;
|
||||
const targetServerName = this._model._migration.targetManagedInstance.name;
|
||||
let targetServerVersion;
|
||||
if (this._model.migrationStatus.id.includes('managedInstances')) {
|
||||
@@ -382,7 +396,7 @@ export class MigrationCutoverDialog {
|
||||
|
||||
this._serverName.value = sqlServerName;
|
||||
this._serverVersion.value = `${sqlServerVersion}
|
||||
${sqlServerEdition}`;
|
||||
${sqlServerInfo.serverVersion}`;
|
||||
|
||||
this._targetServer.value = targetServerName;
|
||||
this._targetVersion.value = targetServerVersion;
|
||||
@@ -396,6 +410,9 @@ export class MigrationCutoverDialog {
|
||||
|
||||
this._fileCount.value = loc.ACTIVE_BACKUP_FILES_ITEMS(tableData.length);
|
||||
|
||||
//Sorting files in descending order of backupStartTime
|
||||
tableData.sort((file1, file2) => new Date(file1.backupStartTime) > new Date(file2.backupStartTime) ? - 1 : 1);
|
||||
|
||||
this.fileTable.data = tableData.map((row) => {
|
||||
return [
|
||||
row.fileName,
|
||||
@@ -411,14 +428,17 @@ export class MigrationCutoverDialog {
|
||||
}
|
||||
|
||||
if (migrationStatusTextValue === 'InProgress') {
|
||||
this._databaseCutoverButton.enabled = true;
|
||||
const fileNotRestored = await tableData.some(file => file.status !== 'Restored');
|
||||
this._cutoverButton.enabled = !fileNotRestored;
|
||||
this._cancelButton.enabled = true;
|
||||
} else {
|
||||
this._databaseCutoverButton.enabled = false;
|
||||
this._cancel.enabled = false;
|
||||
this._cutoverButton.enabled = false;
|
||||
this._cancelButton.enabled = false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
this._refreshLoader.loading = false;
|
||||
}
|
||||
|
||||
private createInfoField(label: string, value: string): {
|
||||
|
||||
@@ -19,6 +19,7 @@ export class MigrationStatusDialog {
|
||||
private _refresh!: azdata.ButtonComponent;
|
||||
private _statusDropdown!: azdata.DropDownComponent;
|
||||
private _statusTable!: azdata.DeclarativeTableComponent;
|
||||
private _refreshLoader!: azdata.LoadingComponent;
|
||||
|
||||
constructor(migrations: MigrationContext[], private _filter: MigrationCategory) {
|
||||
this._model = new MigrationStatusDialogModel(migrations);
|
||||
@@ -102,11 +103,19 @@ export class MigrationStatusDialog {
|
||||
}
|
||||
});
|
||||
|
||||
this._refreshLoader = this._view.modelBuilder.loadingComponent().withProps({
|
||||
loading: false,
|
||||
height: '55px'
|
||||
}).component();
|
||||
|
||||
flexContainer.addItem(this._refreshLoader, {
|
||||
flex: '0'
|
||||
});
|
||||
|
||||
return flexContainer;
|
||||
}
|
||||
|
||||
private populateMigrationTable(): void {
|
||||
|
||||
try {
|
||||
const migrations = this._model.filterMigration(
|
||||
this._searchBox.value!,
|
||||
@@ -115,6 +124,10 @@ export class MigrationStatusDialog {
|
||||
|
||||
const data: azdata.DeclarativeTableCellValue[][] = [];
|
||||
|
||||
migrations.sort((m1, m2) => {
|
||||
return new Date(m1.migrationContext.properties.startedOn) > new Date(m2.migrationContext.properties.startedOn) ? -1 : 1;
|
||||
});
|
||||
|
||||
migrations.forEach((migration) => {
|
||||
const migrationRow: azdata.DeclarativeTableCellValue[] = [];
|
||||
|
||||
@@ -133,8 +146,8 @@ export class MigrationStatusDialog {
|
||||
value: migration.migrationContext.properties.migrationStatus
|
||||
});
|
||||
|
||||
const sqlMigrationIcon = this._view.modelBuilder.image().withProps({
|
||||
iconPath: IconPathHelper.sqlMigrationLogo,
|
||||
const targetMigrationIcon = this._view.modelBuilder.image().withProps({
|
||||
iconPath: (migration.targetManagedInstance.type === 'microsoft.sql/managedinstances') ? IconPathHelper.sqlMiLogo : IconPathHelper.sqlVmLogo,
|
||||
iconWidth: '16px',
|
||||
iconHeight: '16px',
|
||||
width: '32px',
|
||||
@@ -145,7 +158,7 @@ export class MigrationStatusDialog {
|
||||
url: ''
|
||||
}).component();
|
||||
sqlMigrationName.onDidClick((e) => {
|
||||
vscode.window.showInformationMessage('Feature coming soon');
|
||||
vscode.window.showInformationMessage(loc.COMING_SOON);
|
||||
});
|
||||
|
||||
const sqlMigrationContainer = this._view.modelBuilder.flexContainer().withProps({
|
||||
@@ -153,7 +166,7 @@ export class MigrationStatusDialog {
|
||||
'justify-content': 'center'
|
||||
}
|
||||
}).component();
|
||||
sqlMigrationContainer.addItem(sqlMigrationIcon, {
|
||||
sqlMigrationContainer.addItem(targetMigrationIcon, {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'width': '32px'
|
||||
@@ -174,10 +187,10 @@ export class MigrationStatusDialog {
|
||||
});
|
||||
|
||||
migrationRow.push({
|
||||
value: '---'
|
||||
value: (migration.migrationContext.properties.startedOn) ? new Date(migration.migrationContext.properties.startedOn).toLocaleString() : '---'
|
||||
});
|
||||
migrationRow.push({
|
||||
value: '---'
|
||||
value: (migration.migrationContext.properties.endedOn) ? new Date(migration.migrationContext.properties.endedOn).toLocaleString() : '---'
|
||||
});
|
||||
|
||||
data.push(migrationRow);
|
||||
@@ -190,6 +203,7 @@ export class MigrationStatusDialog {
|
||||
}
|
||||
|
||||
private refreshTable(): void {
|
||||
this._refreshLoader.loading = true;
|
||||
this._model._migrations.forEach(async (migration) => {
|
||||
migration.migrationContext = await getDatabaseMigration(
|
||||
migration.azureAccount,
|
||||
@@ -198,8 +212,8 @@ export class MigrationStatusDialog {
|
||||
migration.migrationContext.id
|
||||
);
|
||||
});
|
||||
|
||||
this.populateMigrationTable();
|
||||
this._refreshLoader.loading = false;
|
||||
}
|
||||
|
||||
private createStatusTable(): azdata.DeclarativeTableComponent {
|
||||
|
||||
Reference in New Issue
Block a user