mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 02:32:35 -05:00
Migration extensions - UI fixes and vBump (#15199)
* Fixing Migration Cutover Dialog Adding support for target file share Fixing request body Correcting localized strings * Redesigned IR page Adding additional details in migration status dialog * vbump * Fixed the perpetual loading * Fixed duration logic * Adding icon for migration extension * Adding helper commenst to util function localizing some strings logging console errors * enabling cutover buttons for ignored files
This commit is contained in:
@@ -350,19 +350,8 @@ export interface StartDatabaseMigrationRequest {
|
||||
targetLocation: {
|
||||
storageAccountResourceId: string,
|
||||
accountKey: string,
|
||||
}
|
||||
sourceLocation: {
|
||||
fileShare?: {
|
||||
path: string,
|
||||
username: string,
|
||||
password: string,
|
||||
},
|
||||
azureBlob?: {
|
||||
storageAccountResourceId: string,
|
||||
accountKey: string,
|
||||
blobContainerName: string
|
||||
}
|
||||
},
|
||||
sourceLocation: SourceLocation
|
||||
},
|
||||
sourceSqlConnection: {
|
||||
authentication: string,
|
||||
@@ -454,8 +443,8 @@ export interface BackupSetInfo {
|
||||
}
|
||||
|
||||
export interface SourceLocation {
|
||||
fileShare: DatabaseMigrationFileShare;
|
||||
azureBlob: DatabaseMigrationAzureBlob;
|
||||
fileShare?: DatabaseMigrationFileShare;
|
||||
azureBlob?: DatabaseMigrationAzureBlob;
|
||||
}
|
||||
|
||||
export interface TargetLocation {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DAYS, HRS, MINUTE, SEC } from '../constants/strings';
|
||||
|
||||
export function deepClone<T>(obj: T): T {
|
||||
if (!obj || typeof obj !== 'object') {
|
||||
return obj;
|
||||
@@ -40,3 +42,27 @@ export function getSqlServerName(majorVersion: number): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a wordy time difference between start and end time.
|
||||
* @returns stringified duration like '10.0 days', '12.0 hrs', '1.0 min'
|
||||
*/
|
||||
export function convertTimeDifferenceToDuration(startTime: Date, endTime: Date): string {
|
||||
const time = endTime.getTime() - startTime.getTime();
|
||||
let seconds = (time / 1000).toFixed(1);
|
||||
let minutes = (time / (1000 * 60)).toFixed(1);
|
||||
let hours = (time / (1000 * 60 * 60)).toFixed(1);
|
||||
let days = (time / (1000 * 60 * 60 * 24)).toFixed(1);
|
||||
if (time / 1000 < 60) {
|
||||
return SEC(parseFloat(seconds));
|
||||
}
|
||||
else if (time / (1000 * 60) < 60) {
|
||||
return MINUTE(parseFloat(minutes));
|
||||
}
|
||||
else if (time / (1000 * 60 * 60) < 24) {
|
||||
return HRS(parseFloat(hours));
|
||||
}
|
||||
else {
|
||||
return DAYS(parseFloat(days));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ export const EASTUS2EUAP = localize('sql.migration.eastus2euap', 'East US 2 EUAP
|
||||
|
||||
//Migration cutover dialog
|
||||
export const MIGRATION_CUTOVER = localize('sql.migration.cutover', "Migration cutover");
|
||||
export const SOURCE_DATABASE = localize('sql.migration.source.database', "Source database");
|
||||
export const SOURCE_DATABASE = localize('sql.migration.source.database', "Source database name");
|
||||
export const SOURCE_SERVER = localize('sql.migration.source.server', "Source server");
|
||||
export const SOURCE_VERSION = localize('sql.migration.source.version', "Source version");
|
||||
export const TARGET_DATABASE_NAME = localize('sql.migration.target.database.name', "Target database name");
|
||||
@@ -306,7 +306,12 @@ export const SEARCH_FOR_MIGRATIONS = localize('sql.migration.search.for.migratio
|
||||
export const ONLINE = localize('sql.migration.online', "Online");
|
||||
export const OFFLINE = localize('sql.migration.offline', "Offline");
|
||||
export const DATABASE = localize('sql.migration.database', "Database");
|
||||
export const TARGET_AZURE_SQL_INSTANCE_NAME = localize('sql.migration.target.azure.sql.instance.name', "Target Azure SQL Instance Name");
|
||||
export const DATABASE_MIGRATION_SERVICE = localize('sql.migration.database.migration.service', "Database Migration Service");
|
||||
export const DURATION = localize('sql.migration.duration', "Duration");
|
||||
export const AZURE_SQL_TARGET = localize('sql.migration.azure.sql.target', "Azure SQL Target");
|
||||
export const SQL_MANAGED_INSTANCE = localize('sql.migration.sql.managed.instance', "SQL Managed Instance");
|
||||
export const SQL_VIRTUAL_MACHINE = localize('sql.migration.sql.virtual.machine', "SQL Virtual Machine");
|
||||
export const TARGET_AZURE_SQL_INSTANCE_NAME = localize('sql.migration.target.azure.sql.instance.name', "Azure SQL Target Name");
|
||||
export const MIGRATION_MODE = localize('sql.migration.cutover.type', "Migration Mode");
|
||||
export const START_TIME = localize('sql.migration.start.time', "Start Time");
|
||||
export const FINISH_TIME = localize('sql.migration.finish.time', "Finish Time");
|
||||
@@ -330,7 +335,19 @@ export function STATUS_WARNING_COUNT(status: string, count: number): string {
|
||||
return localize('sql.migration.status.error.count.multiple', "{0} ({1} Errors)", status, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function HRS(hrs: number): string {
|
||||
return hrs > 1 ? localize('sql.migration.hrs', "{0} hrs", hrs) : localize('sql.migration.hr', "{0} hr", hrs);
|
||||
}
|
||||
export function DAYS(days: number): string {
|
||||
return days > 1 ? localize('sql.migration.days', "{0} days", days) : localize('sql.migration.day', "{0} day", days);
|
||||
}
|
||||
export function MINUTE(mins: number): string {
|
||||
return mins > 1 ? localize('sql.migration.mins', "{0} mins", mins) : localize('sql.migration.min', "{0} min", mins);
|
||||
}
|
||||
export function SEC(sec: number): string {
|
||||
return localize('sql.migration.sec', "{0} sec", sec);
|
||||
}
|
||||
|
||||
//Source Credentials page.
|
||||
|
||||
@@ -212,7 +212,7 @@ export class DashboardWidget {
|
||||
height: maxHeight,
|
||||
iconHeight: 32,
|
||||
iconPath: taskMetaData.iconPath,
|
||||
iconWidth: 36,
|
||||
iconWidth: 32,
|
||||
label: taskMetaData.title,
|
||||
title: taskMetaData.title,
|
||||
width: maxWidth,
|
||||
|
||||
@@ -58,7 +58,9 @@ export class CreateSqlMigrationServiceDialog {
|
||||
text: ''
|
||||
};
|
||||
this._statusLoadingComponent.loading = true;
|
||||
this._formSubmitButton.enabled = false;
|
||||
this.migrationServiceResourceGroupDropdown.loading = false;
|
||||
this.setFormEnabledState(false);
|
||||
|
||||
|
||||
const subscription = this.migrationStateModel._targetSubscription;
|
||||
const resourceGroup = (this.migrationServiceResourceGroupDropdown.value as azdata.CategoryValue).name;
|
||||
@@ -70,7 +72,7 @@ export class CreateSqlMigrationServiceDialog {
|
||||
if (formValidationErrors.length > 0) {
|
||||
this.setDialogMessage(formValidationErrors);
|
||||
this._statusLoadingComponent.loading = false;
|
||||
this._formSubmitButton.enabled = true;
|
||||
this.setFormEnabledState(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -79,7 +81,7 @@ export class CreateSqlMigrationServiceDialog {
|
||||
if (this.createdMigrationService.error) {
|
||||
this.setDialogMessage(`${this.createdMigrationService.error.code} : ${this.createdMigrationService.error.message}`);
|
||||
this._statusLoadingComponent.loading = false;
|
||||
this._formSubmitButton.enabled = true;
|
||||
this.setFormEnabledState(true);
|
||||
return;
|
||||
}
|
||||
this._dialogObject.message = {
|
||||
@@ -93,7 +95,7 @@ export class CreateSqlMigrationServiceDialog {
|
||||
console.log(e);
|
||||
this.setDialogMessage(e.message);
|
||||
this._statusLoadingComponent.loading = false;
|
||||
this._formSubmitButton.enabled = true;
|
||||
this.setFormEnabledState(true);
|
||||
return;
|
||||
}
|
||||
});
|
||||
@@ -138,17 +140,24 @@ export class CreateSqlMigrationServiceDialog {
|
||||
this._dialogObject.cancelButton.onClick((e) => {
|
||||
});
|
||||
this._dialogObject.okButton.onClick((e) => {
|
||||
this.irPage.populateMigrationService(this.createdMigrationService, this.createdMigrationServiceNodeNames);
|
||||
this.irPage.populateMigrationService(this.createdMigrationService, this.createdMigrationServiceNodeNames, (this.migrationServiceResourceGroupDropdown.value as azdata.CategoryValue).name);
|
||||
});
|
||||
}
|
||||
|
||||
private async migrationServiceDropdownContainer(): Promise<azdata.FlexContainer> {
|
||||
const dialogDescription = this._view.modelBuilder.text().withProps({
|
||||
value: constants.MIGRATION_SERVICE_DIALOG_DESCRIPTION
|
||||
value: constants.MIGRATION_SERVICE_DIALOG_DESCRIPTION,
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const subscriptionDropdownLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SUBSCRIPTION
|
||||
value: constants.SUBSCRIPTION,
|
||||
CSSStyles: {
|
||||
'font-size': '13px',
|
||||
'font-weight': 'bold'
|
||||
}
|
||||
}).component();
|
||||
|
||||
this.migrationServiceSubscription = this._view.modelBuilder.inputBox().withProps({
|
||||
@@ -157,7 +166,11 @@ export class CreateSqlMigrationServiceDialog {
|
||||
}).component();
|
||||
|
||||
const resourceGroupDropdownLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.RESOURCE_GROUP
|
||||
value: constants.RESOURCE_GROUP,
|
||||
CSSStyles: {
|
||||
'font-size': '13px',
|
||||
'font-weight': 'bold'
|
||||
}
|
||||
}).component();
|
||||
|
||||
this.migrationServiceResourceGroupDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
@@ -165,13 +178,21 @@ export class CreateSqlMigrationServiceDialog {
|
||||
}).component();
|
||||
|
||||
const migrationServiceNameLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.NAME
|
||||
value: constants.NAME,
|
||||
CSSStyles: {
|
||||
'font-size': '13px',
|
||||
'font-weight': 'bold'
|
||||
}
|
||||
}).component();
|
||||
|
||||
this.migrationServiceNameText = this._view.modelBuilder.inputBox().component();
|
||||
|
||||
const locationDropdownLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.LOCATION
|
||||
value: constants.LOCATION,
|
||||
CSSStyles: {
|
||||
'font-size': '13px',
|
||||
'font-weight': 'bold'
|
||||
}
|
||||
}).component();
|
||||
|
||||
this.migrationServiceLocation = this._view.modelBuilder.inputBox().withProps({
|
||||
@@ -181,7 +202,11 @@ export class CreateSqlMigrationServiceDialog {
|
||||
}).component();
|
||||
|
||||
const targetlabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.TARGET
|
||||
value: constants.TARGET,
|
||||
CSSStyles: {
|
||||
'font-size': '13px',
|
||||
'font-weight': 'bold'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const targetText = this._view.modelBuilder.inputBox().withProps({
|
||||
@@ -259,20 +284,30 @@ export class CreateSqlMigrationServiceDialog {
|
||||
const setupIRHeadingText = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SERVICE_CONTAINER_HEADING,
|
||||
CSSStyles: {
|
||||
'font-weight': 'bold'
|
||||
'font-weight': 'bold',
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const setupIRdescription1 = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SERVICE_CONTAINER_DESCRIPTION1,
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const setupIRdescription2 = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SERVICE_CONTAINER_DESCRIPTION2,
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const irSetupStep1Text = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SERVICE_STEP1,
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
},
|
||||
links: [
|
||||
{
|
||||
text: constants.SERVICE_STEP1_LINK,
|
||||
@@ -282,7 +317,10 @@ export class CreateSqlMigrationServiceDialog {
|
||||
}).component();
|
||||
|
||||
const irSetupStep2Text = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SERVICE_STEP2
|
||||
value: constants.SERVICE_STEP2,
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const irSetupStep3Text = this._view.modelBuilder.hyperlink().withProps({
|
||||
@@ -290,7 +328,8 @@ export class CreateSqlMigrationServiceDialog {
|
||||
url: '',
|
||||
CSSStyles: {
|
||||
'margin-top': '10px',
|
||||
'margin-bottom': '10px'
|
||||
'margin-bottom': '10px',
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
@@ -311,14 +350,23 @@ export class CreateSqlMigrationServiceDialog {
|
||||
});
|
||||
|
||||
|
||||
this._connectionStatus = this._view.modelBuilder.infoBox().component();
|
||||
this._connectionStatus = this._view.modelBuilder.infoBox().withProps({
|
||||
text: '',
|
||||
style: 'error',
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
this._connectionStatus.CSSStyles = {
|
||||
'width': '350px'
|
||||
};
|
||||
|
||||
const refreshLoadingIndicator = this._view.modelBuilder.loadingComponent().withProps({
|
||||
loading: false
|
||||
loading: false,
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
|
||||
@@ -330,7 +378,10 @@ export class CreateSqlMigrationServiceDialog {
|
||||
width: '50px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
'text-align': 'center'
|
||||
'font-size': '13px'
|
||||
},
|
||||
headerCssStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -339,20 +390,23 @@ export class CreateSqlMigrationServiceDialog {
|
||||
width: '500px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
overflow: 'scroll'
|
||||
'font-size': '13px'
|
||||
},
|
||||
headerCssStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '15px',
|
||||
isReadOnly: true,
|
||||
},
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '15px',
|
||||
width: '30px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
'font-size': '13px'
|
||||
},
|
||||
headerCssStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
}
|
||||
],
|
||||
CSSStyles: {
|
||||
@@ -399,14 +453,20 @@ export class CreateSqlMigrationServiceDialog {
|
||||
if (state === 'Online') {
|
||||
this._connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.SERVICE_READY(this.createdMigrationService!.name, this.createdMigrationServiceNodeNames.join(', ')),
|
||||
style: 'success'
|
||||
style: 'success',
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
});
|
||||
this._dialogObject.okButton.enabled = true;
|
||||
} else {
|
||||
this._connectionStatus.text = constants.SERVICE_NOT_READY(this.createdMigrationService!.name);
|
||||
this._connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.SERVICE_NOT_READY(this.createdMigrationService!.name),
|
||||
style: 'warning'
|
||||
style: 'warning',
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
});
|
||||
this._dialogObject.okButton.enabled = false;
|
||||
}
|
||||
@@ -461,10 +521,7 @@ export class CreateSqlMigrationServiceDialog {
|
||||
value: keys.authKey1
|
||||
},
|
||||
{
|
||||
value: this._copyKey1Button
|
||||
},
|
||||
{
|
||||
value: this._refreshKey1Button
|
||||
value: this._view.modelBuilder.flexContainer().withItems([this._copyKey1Button, this._refreshKey1Button]).component()
|
||||
}
|
||||
],
|
||||
[
|
||||
@@ -475,10 +532,7 @@ export class CreateSqlMigrationServiceDialog {
|
||||
value: keys.authKey2
|
||||
},
|
||||
{
|
||||
value: this._copyKey2Button
|
||||
},
|
||||
{
|
||||
value: this._refreshKey2Button
|
||||
value: this._view.modelBuilder.flexContainer().withItems([this._copyKey2Button, this._refreshKey2Button]).component()
|
||||
}
|
||||
]
|
||||
]
|
||||
@@ -492,4 +546,10 @@ export class CreateSqlMigrationServiceDialog {
|
||||
level: level
|
||||
};
|
||||
}
|
||||
|
||||
private setFormEnabledState(enable: boolean): void {
|
||||
this._formSubmitButton.enabled = enable;
|
||||
this.migrationServiceResourceGroupDropdown.enabled = enable;
|
||||
this.migrationServiceNameText.enabled = enable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ export class MigrationCutoverDialog {
|
||||
private _targetVersion!: azdata.TextComponent;
|
||||
private _migrationStatus!: azdata.TextComponent;
|
||||
private _fullBackupFile!: azdata.TextComponent;
|
||||
private _backupLocation!: azdata.TextComponent;
|
||||
private _lastAppliedLSN!: azdata.TextComponent;
|
||||
private _lastAppliedBackupFile!: azdata.TextComponent;
|
||||
private _lastAppliedBackupTakenOn!: azdata.TextComponent;
|
||||
@@ -44,7 +45,7 @@ export class MigrationCutoverDialog {
|
||||
|
||||
constructor(migration: MigrationContext) {
|
||||
this._model = new MigrationCutoverDialogModel(migration);
|
||||
this._dialogObject = azdata.window.createModelViewDialog(loc.MIGRATION_CUTOVER, 'MigrationCutoverDialog', 1000);
|
||||
this._dialogObject = azdata.window.createModelViewDialog('', 'MigrationCutoverDialog', 1000);
|
||||
}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
@@ -65,17 +66,17 @@ export class MigrationCutoverDialog {
|
||||
|
||||
flexServer.addItem(sourceDatabase.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '150px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
flexServer.addItem(sourceDetails.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '150px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
flexServer.addItem(sourceVersion.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '150px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -93,26 +94,28 @@ export class MigrationCutoverDialog {
|
||||
|
||||
flexTarget.addItem(targetDatabase.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '230px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
flexTarget.addItem(targetServer.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '230px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
flexTarget.addItem(targetVersion.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '230px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
|
||||
const migrationStatus = this.createInfoField(loc.MIGRATION_STATUS, '');
|
||||
const fullBackupFileOn = this.createInfoField(loc.FULL_BACKUP_FILES, '');
|
||||
const backupLocation = this.createInfoField(loc.BACKUP_LOCATION, '');
|
||||
|
||||
|
||||
this._migrationStatus = migrationStatus.text;
|
||||
this._fullBackupFile = fullBackupFileOn.text;
|
||||
this._backupLocation = backupLocation.text;
|
||||
|
||||
const flexStatus = view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
@@ -120,12 +123,17 @@ export class MigrationCutoverDialog {
|
||||
|
||||
flexStatus.addItem(migrationStatus.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '180px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
flexStatus.addItem(fullBackupFileOn.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '180px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
flexStatus.addItem(backupLocation.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -133,6 +141,7 @@ export class MigrationCutoverDialog {
|
||||
const lastAppliedBackup = this.createInfoField(loc.LAST_APPLIED_BACKUP_FILES, '');
|
||||
const lastAppliedBackupOn = this.createInfoField(loc.LAST_APPLIED_BACKUP_FILES_TAKEN_ON, '');
|
||||
|
||||
|
||||
this._lastAppliedLSN = lastSSN.text;
|
||||
this._lastAppliedBackupFile = lastAppliedBackup.text;
|
||||
this._lastAppliedBackupTakenOn = lastAppliedBackupOn.text;
|
||||
@@ -142,22 +151,22 @@ export class MigrationCutoverDialog {
|
||||
}).component();
|
||||
flexFile.addItem(lastSSN.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '230px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
flexFile.addItem(lastAppliedBackup.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '230px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
flexFile.addItem(lastAppliedBackupOn.flexContainer, {
|
||||
CSSStyles: {
|
||||
'width': '230px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
const flexInfo = view.modelBuilder.flexContainer().withProps({
|
||||
CSSStyles: {
|
||||
'width': '700px'
|
||||
'width': '800px',
|
||||
}
|
||||
}).component();
|
||||
|
||||
@@ -165,7 +174,7 @@ export class MigrationCutoverDialog {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'flex': '0',
|
||||
'width': '150px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -173,7 +182,7 @@ export class MigrationCutoverDialog {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'flex': '0',
|
||||
'width': '230px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -181,7 +190,7 @@ export class MigrationCutoverDialog {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'flex': '0',
|
||||
'width': '180px'
|
||||
'width': '200px'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -240,11 +249,17 @@ export class MigrationCutoverDialog {
|
||||
const formBuilder = view.modelBuilder.formContainer().withFormItems(
|
||||
[
|
||||
{
|
||||
component: await this.migrationContainerHeader()
|
||||
component: this.migrationContainerHeader()
|
||||
},
|
||||
{
|
||||
component: this._view.modelBuilder.separator().withProps({ width: '800px' }).component()
|
||||
},
|
||||
{
|
||||
component: flexInfo
|
||||
},
|
||||
{
|
||||
component: this._view.modelBuilder.separator().withProps({ width: '800px' }).component()
|
||||
},
|
||||
{
|
||||
component: this._fileCount
|
||||
},
|
||||
@@ -267,30 +282,59 @@ export class MigrationCutoverDialog {
|
||||
|
||||
|
||||
private migrationContainerHeader(): azdata.FlexContainer {
|
||||
const header = this._view.modelBuilder.flexContainer().withLayout({
|
||||
const sqlDatbaseLogo = this._view.modelBuilder.image().withProps({
|
||||
iconPath: IconPathHelper.sqlDatabaseLogo,
|
||||
iconHeight: '32px',
|
||||
iconWidth: '32px',
|
||||
width: '32px',
|
||||
height: '32px'
|
||||
}).component();
|
||||
|
||||
this._databaseTitleName = this._view.modelBuilder.text().withProps({
|
||||
CSSStyles: {
|
||||
'font-size': 'large',
|
||||
'width': '400px'
|
||||
'font-size': '16px',
|
||||
'font-weight': 'bold',
|
||||
'margin': '0px'
|
||||
},
|
||||
value: this._model._migration.migrationContext.name
|
||||
value: this._model._migration.migrationContext.properties.sourceDatabaseName
|
||||
}).component();
|
||||
|
||||
header.addItem(this._databaseTitleName, {
|
||||
flex: '0',
|
||||
const databaseSubTitle = this._view.modelBuilder.text().withProps({
|
||||
CSSStyles: {
|
||||
'width': '500px'
|
||||
'font-size': '10px',
|
||||
'margin': '5px 0px'
|
||||
},
|
||||
value: loc.DATABASE
|
||||
}).component();
|
||||
|
||||
const titleContainer = this._view.modelBuilder.flexContainer().withItems([
|
||||
this._databaseTitleName,
|
||||
databaseSubTitle
|
||||
]).withLayout({
|
||||
'flexFlow': 'column'
|
||||
}).component();
|
||||
|
||||
|
||||
const titleLogoContainer = this._view.modelBuilder.flexContainer().component();
|
||||
|
||||
titleLogoContainer.addItem(sqlDatbaseLogo, {
|
||||
flex: '0'
|
||||
});
|
||||
titleLogoContainer.addItem(titleContainer, {
|
||||
CSSStyles: {
|
||||
'margin-left': '5px'
|
||||
}
|
||||
});
|
||||
|
||||
const headerActions = this._view.modelBuilder.flexContainer().withLayout({
|
||||
}).component();
|
||||
|
||||
this._cutoverButton = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.cutover,
|
||||
iconHeight: '14px',
|
||||
iconWidth: '12px',
|
||||
label: 'Start Cutover',
|
||||
height: '55px',
|
||||
height: '20px',
|
||||
width: '100px',
|
||||
enabled: false
|
||||
}).component();
|
||||
@@ -307,11 +351,8 @@ export class MigrationCutoverDialog {
|
||||
}
|
||||
});
|
||||
|
||||
header.addItem(this._cutoverButton, {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'width': '100px'
|
||||
}
|
||||
headerActions.addItem(this._cutoverButton, {
|
||||
flex: '0'
|
||||
});
|
||||
|
||||
this._cancelButton = this._view.modelBuilder.button().withProps({
|
||||
@@ -319,19 +360,16 @@ export class MigrationCutoverDialog {
|
||||
iconHeight: '16px',
|
||||
iconWidth: '16px',
|
||||
label: loc.CANCEL_MIGRATION,
|
||||
height: '55px',
|
||||
width: '130px'
|
||||
height: '20px',
|
||||
width: '120px'
|
||||
}).component();
|
||||
|
||||
this._cancelButton.onDidClick((e) => {
|
||||
this.cancelMigration();
|
||||
});
|
||||
|
||||
header.addItem(this._cancelButton, {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'width': '130px'
|
||||
}
|
||||
headerActions.addItem(this._cancelButton, {
|
||||
flex: '0'
|
||||
});
|
||||
|
||||
|
||||
@@ -340,19 +378,16 @@ export class MigrationCutoverDialog {
|
||||
iconHeight: '16px',
|
||||
iconWidth: '16px',
|
||||
label: 'Refresh',
|
||||
height: '55px',
|
||||
width: '100px'
|
||||
height: '20px',
|
||||
width: '65px'
|
||||
}).component();
|
||||
|
||||
this._refreshButton.onDidClick((e) => {
|
||||
this.refreshStatus();
|
||||
});
|
||||
|
||||
header.addItem(this._refreshButton, {
|
||||
headerActions.addItem(this._refreshButton, {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'width': '100px'
|
||||
}
|
||||
});
|
||||
|
||||
this._copyDatabaseMigrationDetails = this._view.modelBuilder.button().withProps({
|
||||
@@ -360,8 +395,8 @@ export class MigrationCutoverDialog {
|
||||
iconHeight: '16px',
|
||||
iconWidth: '16px',
|
||||
label: loc.COPY_MIGRATION_DETAILS,
|
||||
height: '55px',
|
||||
width: '100px'
|
||||
height: '20px',
|
||||
width: '150px'
|
||||
}).component();
|
||||
|
||||
this._copyDatabaseMigrationDetails.onDidClick(async (e) => {
|
||||
@@ -378,22 +413,34 @@ export class MigrationCutoverDialog {
|
||||
vscode.window.showInformationMessage(loc.DETAILS_COPIED);
|
||||
});
|
||||
|
||||
header.addItem(this._copyDatabaseMigrationDetails, {
|
||||
headerActions.addItem(this._copyDatabaseMigrationDetails, {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'width': '100px'
|
||||
'margin-left': '5px'
|
||||
}
|
||||
});
|
||||
|
||||
this._refreshLoader = this._view.modelBuilder.loadingComponent().withProps({
|
||||
loading: false,
|
||||
height: '55px'
|
||||
height: '15px'
|
||||
}).component();
|
||||
|
||||
header.addItem(this._refreshLoader, {
|
||||
headerActions.addItem(this._refreshLoader, {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'margin-top': '15px'
|
||||
'margin-left': '16px'
|
||||
}
|
||||
});
|
||||
|
||||
const header = this._view.modelBuilder.flexContainer().withItems([
|
||||
titleLogoContainer
|
||||
]).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
|
||||
header.addItem(headerActions, {
|
||||
'CSSStyles': {
|
||||
'margin-top': '16px'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -461,19 +508,19 @@ export class MigrationCutoverDialog {
|
||||
|
||||
this._sourceDatabase.value = sourceDatabaseName;
|
||||
this._serverName.value = sqlServerName;
|
||||
this._serverVersion.value = `${sqlServerVersion}
|
||||
${sqlServerInfo.serverVersion}`;
|
||||
this._serverVersion.value = `${sqlServerVersion} ${sqlServerInfo.serverVersion}`;
|
||||
|
||||
this._targetDatabase.value = targetDatabaseName;
|
||||
this._targetServer.value = targetServerName;
|
||||
this._targetVersion.value = targetServerVersion;
|
||||
|
||||
this._migrationStatus.value = migrationStatusTextValue;
|
||||
this._fullBackupFile.value = fullBackupFileName!;
|
||||
this._migrationStatus.value = migrationStatusTextValue ?? '---';
|
||||
this._fullBackupFile.value = fullBackupFileName! ?? '-';
|
||||
this._backupLocation.value = this._model._migration.migrationContext.properties.backupConfiguration?.sourceLocation?.fileShare?.path! ?? '-';
|
||||
|
||||
this._lastAppliedLSN.value = lastAppliedSSN!;
|
||||
this._lastAppliedBackupFile.value = this._model.migrationStatus.properties.migrationStatusDetails?.lastRestoredFilename;
|
||||
this._lastAppliedBackupTakenOn.value = lastAppliedBackupFileTakenOn! ? new Date(lastAppliedBackupFileTakenOn).toLocaleString() : '';
|
||||
this._lastAppliedLSN.value = lastAppliedSSN! ?? '-';
|
||||
this._lastAppliedBackupFile.value = this._model.migrationStatus.properties.migrationStatusDetails?.lastRestoredFilename ?? '-';
|
||||
this._lastAppliedBackupTakenOn.value = lastAppliedBackupFileTakenOn! ? new Date(lastAppliedBackupFileTakenOn).toLocaleString() : '-';
|
||||
|
||||
this._fileCount.value = loc.ACTIVE_BACKUP_FILES_ITEMS(tableData.length);
|
||||
|
||||
@@ -495,7 +542,7 @@ export class MigrationCutoverDialog {
|
||||
}
|
||||
|
||||
if (migrationStatusTextValue === MigrationStatus.InProgress) {
|
||||
const fileNotRestored = await tableData.some(file => file.status !== 'Restored');
|
||||
const fileNotRestored = await tableData.some(file => file.status !== 'Restored' && file.status !== 'Ignored');
|
||||
this._cutoverButton.enabled = !fileNotRestored;
|
||||
this._cancelButton.enabled = true;
|
||||
} else {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { MigrationContext, MigrationLocalStorage } from '../../models/migrationL
|
||||
import { MigrationCutoverDialog } from '../migrationCutover/migrationCutoverDialog';
|
||||
import { MigrationCategory, MigrationStatusDialogModel } from './migrationStatusDialogModel';
|
||||
import * as loc from '../../constants/strings';
|
||||
import { convertTimeDifferenceToDuration } from '../../api/utils';
|
||||
export class MigrationStatusDialog {
|
||||
private _model: MigrationStatusDialogModel;
|
||||
private _dialogObject!: azdata.window.Dialog;
|
||||
@@ -138,7 +139,7 @@ export class MigrationStatusDialog {
|
||||
const migrationRow: azdata.DeclarativeTableCellValue[] = [];
|
||||
|
||||
const databaseHyperLink = this._view.modelBuilder.hyperlink().withProps({
|
||||
label: migration.migrationContext.name,
|
||||
label: migration.migrationContext.properties.sourceDatabaseName,
|
||||
url: ''
|
||||
}).component();
|
||||
databaseHyperLink.onDidClick(async (e) => {
|
||||
@@ -148,13 +149,10 @@ export class MigrationStatusDialog {
|
||||
value: databaseHyperLink,
|
||||
});
|
||||
|
||||
const targetMigrationIcon = this._view.modelBuilder.image().withProps({
|
||||
iconPath: (migration.targetManagedInstance.type === 'microsoft.sql/managedinstances') ? IconPathHelper.sqlMiLogo : IconPathHelper.sqlVmLogo,
|
||||
iconWidth: '16px',
|
||||
iconHeight: '16px',
|
||||
width: '32px',
|
||||
height: '20px'
|
||||
}).component();
|
||||
migrationRow.push({
|
||||
value: (migration.targetManagedInstance.type === 'microsoft.sql/managedinstances') ? loc.SQL_MANAGED_INSTANCE : loc.SQL_VIRTUAL_MACHINE
|
||||
});
|
||||
|
||||
const sqlMigrationName = this._view.modelBuilder.hyperlink().withProps({
|
||||
label: migration.targetManagedInstance.name,
|
||||
url: ''
|
||||
@@ -163,25 +161,20 @@ export class MigrationStatusDialog {
|
||||
vscode.window.showInformationMessage(loc.COMING_SOON);
|
||||
});
|
||||
|
||||
const sqlMigrationContainer = this._view.modelBuilder.flexContainer().withProps({
|
||||
CSSStyles: {
|
||||
'justify-content': 'left'
|
||||
}
|
||||
}).component();
|
||||
sqlMigrationContainer.addItem(targetMigrationIcon, {
|
||||
flex: '0',
|
||||
CSSStyles: {
|
||||
'width': '32px'
|
||||
}
|
||||
});
|
||||
sqlMigrationContainer.addItem(sqlMigrationName,
|
||||
{
|
||||
CSSStyles: {
|
||||
'width': 'auto'
|
||||
}
|
||||
});
|
||||
migrationRow.push({
|
||||
value: sqlMigrationContainer
|
||||
value: sqlMigrationName
|
||||
});
|
||||
|
||||
const dms = this._view.modelBuilder.hyperlink().withProps({
|
||||
label: migration.controller.name,
|
||||
url: ''
|
||||
}).component();
|
||||
dms.onDidClick((e) => {
|
||||
vscode.window.showInformationMessage(loc.COMING_SOON);
|
||||
});
|
||||
|
||||
migrationRow.push({
|
||||
value: dms
|
||||
});
|
||||
|
||||
migrationRow.push({
|
||||
@@ -209,6 +202,17 @@ export class MigrationStatusDialog {
|
||||
value: loc.STATUS_WARNING_COUNT(migrationStatus, warningCount)
|
||||
});
|
||||
|
||||
let duration;
|
||||
if (migration.migrationContext.properties.endedOn) {
|
||||
duration = convertTimeDifferenceToDuration(new Date(migration.migrationContext.properties.startedOn), new Date(migration.migrationContext.properties.endedOn));
|
||||
} else {
|
||||
duration = convertTimeDifferenceToDuration(new Date(migration.migrationContext.properties.startedOn), new Date());
|
||||
}
|
||||
|
||||
migrationRow.push({
|
||||
value: (migration.migrationContext.properties.startedOn) ? duration : '---'
|
||||
});
|
||||
|
||||
migrationRow.push({
|
||||
value: (migration.migrationContext.properties.startedOn) ? new Date(migration.migrationContext.properties.startedOn).toLocaleString() : '---'
|
||||
});
|
||||
@@ -237,14 +241,16 @@ export class MigrationStatusDialog {
|
||||
const rowCssStyle: azdata.CssStyles = {
|
||||
'border': 'none',
|
||||
'text-align': 'left',
|
||||
'border-bottom': '1px solid'
|
||||
'border-bottom': '1px solid',
|
||||
};
|
||||
|
||||
const headerCssStyles: azdata.CssStyles = {
|
||||
'border': 'none',
|
||||
'text-align': 'left',
|
||||
'border-bottom': '1px solid',
|
||||
'font-weight': 'bold'
|
||||
'font-weight': 'bold',
|
||||
'padding-left': '0px',
|
||||
'padding-right': '0px'
|
||||
};
|
||||
|
||||
this._statusTable = this._view.modelBuilder.declarativeTable().withProps({
|
||||
@@ -252,7 +258,15 @@ export class MigrationStatusDialog {
|
||||
{
|
||||
displayName: loc.DATABASE,
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '100px',
|
||||
width: '90px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: rowCssStyle,
|
||||
headerCssStyles: headerCssStyles
|
||||
},
|
||||
{
|
||||
displayName: loc.AZURE_SQL_TARGET,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '140px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: rowCssStyle,
|
||||
headerCssStyles: headerCssStyles
|
||||
@@ -260,7 +274,15 @@ export class MigrationStatusDialog {
|
||||
{
|
||||
displayName: loc.TARGET_AZURE_SQL_INSTANCE_NAME,
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '170px',
|
||||
width: '160px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: rowCssStyle,
|
||||
headerCssStyles: headerCssStyles
|
||||
},
|
||||
{
|
||||
displayName: loc.DATABASE_MIGRATION_SERVICE,
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '150px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: rowCssStyle,
|
||||
headerCssStyles: headerCssStyles
|
||||
@@ -281,6 +303,14 @@ export class MigrationStatusDialog {
|
||||
rowCssStyles: rowCssStyle,
|
||||
headerCssStyles: headerCssStyles
|
||||
},
|
||||
{
|
||||
displayName: loc.DURATION,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '55px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: rowCssStyle,
|
||||
headerCssStyles: headerCssStyles
|
||||
},
|
||||
{
|
||||
displayName: loc.START_TIME,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
|
||||
@@ -27,11 +27,13 @@ export class MigrationLocalStorage {
|
||||
if (migration.sourceConnectionProfile.serverName === connectionProfile.serverName) {
|
||||
if (refreshStatus) {
|
||||
try {
|
||||
const backupConfiguration = migration.migrationContext.properties.backupConfiguration;
|
||||
migration.migrationContext = await getMigrationStatus(
|
||||
migration.azureAccount,
|
||||
migration.subscription,
|
||||
migration.migrationContext
|
||||
);
|
||||
migration.migrationContext.properties.backupConfiguration = backupConfiguration;
|
||||
if (migration.asyncUrl) {
|
||||
migration.asyncOperationResult = await getMigrationAsyncOperationDetails(
|
||||
migration.azureAccount,
|
||||
|
||||
@@ -602,10 +602,10 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
}
|
||||
|
||||
|
||||
public async getSqlMigrationServiceValues(subscription: azureResource.AzureResourceSubscription, managedInstance: SqlManagedInstance): Promise<azdata.CategoryValue[]> {
|
||||
public async getSqlMigrationServiceValues(subscription: azureResource.AzureResourceSubscription, managedInstance: SqlManagedInstance, resourceGroupName: string): Promise<azdata.CategoryValue[]> {
|
||||
let sqlMigrationServiceValues: azdata.CategoryValue[] = [];
|
||||
try {
|
||||
this._sqlMigrationServices = (await getSqlMigrationServices(this._azureAccount, subscription, managedInstance.location)).filter(sms => sms.location.toLowerCase() === this._targetServerInstance.location.toLowerCase());
|
||||
this._sqlMigrationServices = (await getSqlMigrationServices(this._azureAccount, subscription, managedInstance.location)).filter(sms => sms.location.toLowerCase() === this._targetServerInstance.location.toLowerCase() && sms.properties.resourceGroup.toLowerCase() === resourceGroupName?.toLowerCase());
|
||||
this._sqlMigrationServices.forEach((sqlMigrationService) => {
|
||||
sqlMigrationServiceValues.push({
|
||||
name: sqlMigrationService.id,
|
||||
@@ -687,6 +687,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
this._targetDatabaseNames[i],
|
||||
requestBody
|
||||
);
|
||||
response.databaseMigration.properties.backupConfiguration = requestBody.properties.backupConfiguration!;
|
||||
if (response.status === 201 || response.status === 200) {
|
||||
MigrationLocalStorage.saveMigration(
|
||||
currentConnection!,
|
||||
|
||||
@@ -48,23 +48,26 @@ export class AccountsSelectionPage extends MigrationWizardPage {
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH
|
||||
})
|
||||
.withValidation((c) => {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR) {
|
||||
if (c.value) {
|
||||
if ((<azdata.CategoryValue>c.value).displayName === constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR) {
|
||||
this.wizard.message = {
|
||||
text: constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR,
|
||||
level: azdata.window.MessageLevel.Error
|
||||
};
|
||||
return false;
|
||||
}
|
||||
if (this.migrationStateModel._azureAccount?.isStale) {
|
||||
this.wizard.message = {
|
||||
text: constants.ACCOUNT_STALE_ERROR(this.migrationStateModel._azureAccount)
|
||||
};
|
||||
return false;
|
||||
}
|
||||
this.wizard.message = {
|
||||
text: constants.ACCOUNT_SELECTION_PAGE_NO_LINKED_ACCOUNTS_ERROR,
|
||||
level: azdata.window.MessageLevel.Error
|
||||
text: ''
|
||||
};
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
if (this.migrationStateModel._azureAccount?.isStale) {
|
||||
this.wizard.message = {
|
||||
text: constants.ACCOUNT_STALE_ERROR(this.migrationStateModel._azureAccount)
|
||||
};
|
||||
return false;
|
||||
}
|
||||
this.wizard.message = {
|
||||
text: ''
|
||||
};
|
||||
return true;
|
||||
return false;
|
||||
}).component();
|
||||
|
||||
this._azureAccountsDropdown.onValueChanged(async (value) => {
|
||||
|
||||
@@ -9,17 +9,30 @@ import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
|
||||
import { CreateSqlMigrationServiceDialog } from '../dialog/createSqlMigrationService/createSqlMigrationServiceDialog';
|
||||
import * as constants from '../constants/strings';
|
||||
import { createInformationRow, WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
||||
import { getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlMigrationService } from '../api/azure';
|
||||
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
||||
import { getLocationDisplayName, getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlMigrationService } from '../api/azure';
|
||||
import { IconPathHelper } from '../constants/iconPathHelper';
|
||||
|
||||
export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
|
||||
private migrationServiceDropdown!: azdata.DropDownComponent;
|
||||
private _view!: azdata.ModelView;
|
||||
private _form!: azdata.FormBuilder;
|
||||
private _statusLoadingComponent!: azdata.LoadingComponent;
|
||||
private _migrationDetailsContainer!: azdata.FlexContainer;
|
||||
private _subscription!: azdata.InputBoxComponent;
|
||||
private _location!: azdata.InputBoxComponent;
|
||||
private _resourceGroupDropdown!: azdata.DropDownComponent;
|
||||
private _dmsDropdown!: azdata.DropDownComponent;
|
||||
|
||||
private _dmsStatusInfoBox!: azdata.InfoBoxComponent;
|
||||
private _authKeyTable!: azdata.DeclarativeTableComponent;
|
||||
private _refreshButton!: azdata.ButtonComponent;
|
||||
private _connectionStatusLoader!: azdata.LoadingComponent;
|
||||
|
||||
private _copy1!: azdata.ButtonComponent;
|
||||
private _copy2!: azdata.ButtonComponent;
|
||||
private _refresh1!: azdata.ButtonComponent;
|
||||
private _refresh2!: azdata.ButtonComponent;
|
||||
|
||||
|
||||
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
|
||||
super(wizard, azdata.window.createWizardPage(constants.IR_PAGE_TITLE), migrationStateModel);
|
||||
@@ -30,7 +43,10 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
|
||||
const createNewMigrationService = view.modelBuilder.hyperlink().withProps({
|
||||
label: constants.CREATE_NEW,
|
||||
url: ''
|
||||
url: '',
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
createNewMigrationService.onDidClick((e) => {
|
||||
@@ -38,10 +54,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
dialog.initialize();
|
||||
});
|
||||
|
||||
this._migrationDetailsContainer = view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
this._statusLoadingComponent = view.modelBuilder.loadingComponent().withItem(this._migrationDetailsContainer).component();
|
||||
this._statusLoadingComponent = view.modelBuilder.loadingComponent().withItem(this.createDMSDetailsContainer()).component();
|
||||
|
||||
this._form = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
@@ -104,60 +117,305 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
|
||||
private migrationServiceDropdownContainer(): azdata.FlexContainer {
|
||||
const descriptionText = this._view.modelBuilder.text().withProps({
|
||||
value: constants.IR_PAGE_DESCRIPTION
|
||||
value: constants.IR_PAGE_DESCRIPTION,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
CSSStyles: {
|
||||
'font-size': '13px',
|
||||
}
|
||||
}).component();
|
||||
|
||||
const subscriptionLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SUBSCRIPTION,
|
||||
CSSStyles: {
|
||||
'font-size': '13px',
|
||||
'font-weight': 'bold',
|
||||
}
|
||||
}).component();
|
||||
this._subscription = this._view.modelBuilder.inputBox().withProps({
|
||||
enabled: false,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
}).component();
|
||||
|
||||
const locationLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.LOCATION,
|
||||
CSSStyles: {
|
||||
'font-size': '13px',
|
||||
'font-weight': 'bold',
|
||||
}
|
||||
}).component();
|
||||
this._location = this._view.modelBuilder.inputBox().withProps({
|
||||
enabled: false,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
}).component();
|
||||
|
||||
|
||||
const resourceGroupLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.RESOURCE_GROUP,
|
||||
CSSStyles: {
|
||||
'font-size': '13px',
|
||||
'font-weight': 'bold',
|
||||
}
|
||||
}).component();
|
||||
this._resourceGroupDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
editable: true
|
||||
}).component();
|
||||
|
||||
this._resourceGroupDropdown.onValueChanged(async (value) => {
|
||||
if (value) {
|
||||
this.populateDms(value);
|
||||
}
|
||||
});
|
||||
|
||||
const migrationServcieDropdownLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SELECT_A_SQL_MIGRATION_SERVICE
|
||||
value: constants.IR_PAGE_TITLE,
|
||||
CSSStyles: {
|
||||
'font-size': '13px',
|
||||
'font-weight': 'bold',
|
||||
}
|
||||
}).component();
|
||||
|
||||
this.migrationServiceDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
this._dmsDropdown = this._view.modelBuilder.dropDown().withProps({
|
||||
required: true,
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
editable: true
|
||||
}).component();
|
||||
|
||||
this.migrationServiceDropdown.onValueChanged(async (value) => {
|
||||
if (value.selected) {
|
||||
this._dmsDropdown.onValueChanged(async (value) => {
|
||||
if (value && value !== constants.SQL_MIGRATION_SERVICE_NOT_FOUND_ERROR) {
|
||||
this.wizard.message = {
|
||||
text: ''
|
||||
};
|
||||
this.migrationStateModel._sqlMigrationService = this.migrationStateModel.getMigrationService(value.index);
|
||||
if (value !== constants.SQL_MIGRATION_SERVICE_NOT_FOUND_ERROR) {
|
||||
await this.loadMigrationServiceStatus();
|
||||
}
|
||||
const selectedIndex = (<azdata.CategoryValue[]>this._dmsDropdown.values)?.findIndex((v) => v.displayName === value);
|
||||
this.migrationStateModel._sqlMigrationService = this.migrationStateModel.getMigrationService(selectedIndex);
|
||||
this.loadMigrationServiceStatus();
|
||||
}
|
||||
});
|
||||
|
||||
const flexContainer = this._view.modelBuilder.flexContainer().withItems([
|
||||
descriptionText,
|
||||
subscriptionLabel,
|
||||
this._subscription,
|
||||
locationLabel,
|
||||
this._location,
|
||||
resourceGroupLabel,
|
||||
this._resourceGroupDropdown,
|
||||
migrationServcieDropdownLabel,
|
||||
this.migrationServiceDropdown
|
||||
this._dmsDropdown
|
||||
]).withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
return flexContainer;
|
||||
}
|
||||
|
||||
public async populateMigrationService(sqlMigrationService?: SqlMigrationService, serviceNodes?: string[]): Promise<void> {
|
||||
this.migrationServiceDropdown.loading = true;
|
||||
private createDMSDetailsContainer(): azdata.FlexContainer {
|
||||
const container = this._view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
|
||||
const connectionStatusLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SERVICE_CONNECTION_STATUS,
|
||||
CSSStyles: {
|
||||
'font-weight': 'bold',
|
||||
'font-size': '13px',
|
||||
'width': '130px',
|
||||
'margin': '0'
|
||||
}
|
||||
}).component();
|
||||
|
||||
this._refreshButton = this._view.modelBuilder.button().withProps({
|
||||
iconWidth: '18px',
|
||||
iconHeight: '18px',
|
||||
iconPath: IconPathHelper.refresh,
|
||||
height: '18px',
|
||||
width: '18px'
|
||||
}).component();
|
||||
|
||||
this._refreshButton.onDidClick((e) => {
|
||||
this.loadStatus();
|
||||
});
|
||||
|
||||
const connectionLabelContainer = this._view.modelBuilder.flexContainer().withProps({
|
||||
CSSStyles: {
|
||||
'margin-bottom': '13px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
connectionLabelContainer.addItem(connectionStatusLabel, {
|
||||
flex: '0'
|
||||
});
|
||||
|
||||
connectionLabelContainer.addItem(this._refreshButton, {
|
||||
flex: '0',
|
||||
CSSStyles: { 'margin-right': '10px' }
|
||||
});
|
||||
|
||||
const statusContainer = this._view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column'
|
||||
}).component();
|
||||
|
||||
this._dmsStatusInfoBox = this._view.modelBuilder.infoBox().withProps({
|
||||
width: WIZARD_INPUT_COMPONENT_WIDTH,
|
||||
style: 'error',
|
||||
text: '',
|
||||
CSSStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).withValidation(component => {
|
||||
if (component.style === 'error') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
|
||||
const authenticationKeysLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.AUTHENTICATION_KEYS,
|
||||
CSSStyles: {
|
||||
'font-weight': 'bold',
|
||||
'font-size': '13px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
|
||||
this._copy1 = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.copy,
|
||||
}).component();
|
||||
|
||||
this._copy1.onDidClick(async (e) => {
|
||||
await vscode.env.clipboard.writeText(<string>this._authKeyTable.dataValues![0][1].value);
|
||||
vscode.window.showInformationMessage(constants.SERVICE_KEY_COPIED_HELP);
|
||||
});
|
||||
|
||||
this._copy2 = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.copy
|
||||
}).component();
|
||||
|
||||
this._copy2.onDidClick(async (e) => {
|
||||
await vscode.env.clipboard.writeText(<string>this._authKeyTable.dataValues![1][1].value);
|
||||
vscode.window.showInformationMessage(constants.SERVICE_KEY_COPIED_HELP);
|
||||
});
|
||||
|
||||
this._refresh1 = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.refresh
|
||||
}).component();
|
||||
|
||||
this._refresh2 = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.refresh,
|
||||
}).component();
|
||||
|
||||
this._authKeyTable = this._view.modelBuilder.declarativeTable().withProps({
|
||||
columns: [
|
||||
{
|
||||
displayName: constants.NAME,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '50px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
'font-size': '13px'
|
||||
},
|
||||
headerCssStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: constants.AUTH_KEY_COLUMN_HEADER,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '500px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
'font-size': '13px',
|
||||
|
||||
},
|
||||
headerCssStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '30px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
'font-size': '13px'
|
||||
},
|
||||
headerCssStyles: {
|
||||
'font-size': '13px'
|
||||
}
|
||||
}
|
||||
],
|
||||
CSSStyles: {
|
||||
'margin-top': '5px',
|
||||
'width': WIZARD_INPUT_COMPONENT_WIDTH
|
||||
}
|
||||
}).component();
|
||||
|
||||
statusContainer.addItems([
|
||||
this._dmsStatusInfoBox,
|
||||
authenticationKeysLabel,
|
||||
this._authKeyTable
|
||||
]);
|
||||
|
||||
this._connectionStatusLoader = this._view.modelBuilder.loadingComponent().withItem(
|
||||
statusContainer
|
||||
).component();
|
||||
|
||||
container.addItems(
|
||||
[
|
||||
connectionLabelContainer,
|
||||
this._connectionStatusLoader
|
||||
]
|
||||
);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
public async populateMigrationService(sqlMigrationService?: SqlMigrationService, serviceNodes?: string[], resourceGroupName?: string): Promise<void> {
|
||||
this._resourceGroupDropdown.loading = true;
|
||||
this._dmsDropdown.loading = true;
|
||||
if (sqlMigrationService && serviceNodes) {
|
||||
this.migrationStateModel._sqlMigrationService = sqlMigrationService;
|
||||
this.migrationStateModel._nodeNames = serviceNodes;
|
||||
}
|
||||
|
||||
try {
|
||||
this.migrationServiceDropdown.values = await this.migrationStateModel.getSqlMigrationServiceValues(this.migrationStateModel._targetSubscription, this.migrationStateModel._targetServerInstance);
|
||||
if (this.migrationStateModel._sqlMigrationService) {
|
||||
this.migrationServiceDropdown.value = {
|
||||
name: this.migrationStateModel._sqlMigrationService.id,
|
||||
displayName: this.migrationStateModel._sqlMigrationService.name
|
||||
};
|
||||
this._subscription.value = this.migrationStateModel._targetSubscription.name;
|
||||
this._location.value = await getLocationDisplayName(this.migrationStateModel._targetServerInstance.location);
|
||||
this._resourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._targetSubscription);
|
||||
if (resourceGroupName) {
|
||||
const index = (<azdata.CategoryValue[]>this._resourceGroupDropdown.values).findIndex(v => v.displayName.toLowerCase() === resourceGroupName.toLowerCase());
|
||||
if (resourceGroupName.toLowerCase() === (<azdata.CategoryValue>this._resourceGroupDropdown.value).displayName.toLowerCase()) {
|
||||
this.populateDms(resourceGroupName);
|
||||
} else {
|
||||
this._resourceGroupDropdown.value = this._resourceGroupDropdown.values[index];
|
||||
}
|
||||
} else {
|
||||
this.migrationStateModel._sqlMigrationService = this.migrationStateModel.getMigrationService(0);
|
||||
this._resourceGroupDropdown.value = this._resourceGroupDropdown.values[0];
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
this.migrationServiceDropdown.loading = false;
|
||||
this._resourceGroupDropdown.loading = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async populateDms(resourceGroupName: string): Promise<void> {
|
||||
this._dmsDropdown.loading = true;
|
||||
try {
|
||||
this._dmsDropdown.values = await this.migrationStateModel.getSqlMigrationServiceValues(this.migrationStateModel._targetSubscription, this.migrationStateModel._targetServerInstance, resourceGroupName);
|
||||
let index = -1;
|
||||
if (this.migrationStateModel._sqlMigrationService) {
|
||||
index = (<azdata.CategoryValue[]>this._dmsDropdown.values).findIndex(v => v.displayName.toLowerCase() === this.migrationStateModel._sqlMigrationService.name.toLowerCase());
|
||||
}
|
||||
if (index !== -1) {
|
||||
this._dmsDropdown.value = this._dmsDropdown.values[index];
|
||||
} else {
|
||||
this._dmsDropdown.value = this._dmsDropdown.values[0];
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
} finally {
|
||||
this._dmsDropdown.loading = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -165,8 +423,17 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
private async loadMigrationServiceStatus(): Promise<void> {
|
||||
this._statusLoadingComponent.loading = true;
|
||||
try {
|
||||
this._migrationDetailsContainer.clearItems();
|
||||
await this.loadStatus();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
this._statusLoadingComponent.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async loadStatus(): Promise<void> {
|
||||
this._connectionStatusLoader.loading = true;
|
||||
try {
|
||||
if (this.migrationStateModel._sqlMigrationService) {
|
||||
const migrationService = await getSqlMigrationService(
|
||||
this.migrationStateModel._azureAccount,
|
||||
@@ -181,9 +448,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
this.migrationStateModel._sqlMigrationService.properties.resourceGroup,
|
||||
this.migrationStateModel._sqlMigrationService.location,
|
||||
this.migrationStateModel._sqlMigrationService!.name);
|
||||
this.migrationStateModel._nodeNames = migrationServiceMonitoringStatus.nodes.map((node) => {
|
||||
return node.nodeName;
|
||||
});
|
||||
this.migrationStateModel._nodeNames = migrationServiceMonitoringStatus.nodes.map(node => node.nodeName);
|
||||
const migrationServiceAuthKeys = await getSqlMigrationServiceAuthKeys(
|
||||
this.migrationStateModel._azureAccount,
|
||||
this.migrationStateModel._targetSubscription,
|
||||
@@ -192,228 +457,61 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
this.migrationStateModel._sqlMigrationService!.name
|
||||
);
|
||||
|
||||
const migrationServiceTitle = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SQL_MIGRATION_SERVICE_DETAILS_HEADER(migrationService.name),
|
||||
CSSStyles: {
|
||||
'font-weight': 'bold'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const connectionStatusLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.SERVICE_CONNECTION_STATUS,
|
||||
CSSStyles: {
|
||||
'font-weight': 'bold',
|
||||
'width': '150px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
const refreshStatus = this._view.modelBuilder.button().withProps({
|
||||
label: constants.REFRESH,
|
||||
secondary: true,
|
||||
width: '50px'
|
||||
}).component();
|
||||
|
||||
|
||||
|
||||
const connectionLabelContainer = this._view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'row',
|
||||
alignItems: 'center'
|
||||
}).withItems(
|
||||
[
|
||||
connectionStatusLabel,
|
||||
refreshStatus
|
||||
],
|
||||
{
|
||||
CSSStyles: { 'margin-right': '5px' }
|
||||
}
|
||||
).component();
|
||||
|
||||
const connectionStatus = this._view.modelBuilder.infoBox().component();
|
||||
const connectionStatusLoader = this._view.modelBuilder.loadingComponent().withItem(connectionStatus).withProps({
|
||||
loading: false
|
||||
}).component();
|
||||
refreshStatus.onDidClick(async (e) => {
|
||||
connectionStatusLoader.loading = true;
|
||||
|
||||
const migrationService = await getSqlMigrationService(
|
||||
this.migrationStateModel._azureAccount,
|
||||
this.migrationStateModel._targetSubscription,
|
||||
this.migrationStateModel._sqlMigrationService.properties.resourceGroup,
|
||||
this.migrationStateModel._sqlMigrationService.location,
|
||||
this.migrationStateModel._sqlMigrationService.name);
|
||||
this.migrationStateModel._sqlMigrationService = migrationService;
|
||||
const migrationServiceMonitoringStatus = await getSqlMigrationServiceMonitoringData(
|
||||
this.migrationStateModel._azureAccount,
|
||||
this.migrationStateModel._targetSubscription,
|
||||
this.migrationStateModel._sqlMigrationService.properties.resourceGroup,
|
||||
this.migrationStateModel._sqlMigrationService.location,
|
||||
this.migrationStateModel._sqlMigrationService!.name);
|
||||
this.migrationStateModel._nodeNames = migrationServiceMonitoringStatus.nodes.map((node) => {
|
||||
return node.nodeName;
|
||||
});
|
||||
|
||||
const state = migrationService.properties.integrationRuntimeState;
|
||||
if (state === 'Online') {
|
||||
connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.SERVICE_READY(this.migrationStateModel._sqlMigrationService!.name, this.migrationStateModel._nodeNames.join(', ')),
|
||||
style: 'success'
|
||||
});
|
||||
} else {
|
||||
connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.SERVICE_NOT_READY(this.migrationStateModel._sqlMigrationService!.name),
|
||||
style: 'error'
|
||||
});
|
||||
}
|
||||
|
||||
connectionStatusLoader.loading = false;
|
||||
this.migrationStateModel._nodeNames = migrationServiceMonitoringStatus.nodes.map((node) => {
|
||||
return node.nodeName;
|
||||
});
|
||||
|
||||
const state = migrationService.properties.integrationRuntimeState;
|
||||
if (migrationService) {
|
||||
if (state === 'Online') {
|
||||
connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.SERVICE_READY(this.migrationStateModel._sqlMigrationService!.name, this.migrationStateModel._nodeNames.join(', ')),
|
||||
style: 'success'
|
||||
});
|
||||
} else {
|
||||
connectionStatus.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.SERVICE_NOT_READY(this.migrationStateModel._sqlMigrationService!.name),
|
||||
style: 'error'
|
||||
});
|
||||
}
|
||||
if (state === 'Online') {
|
||||
this._dmsStatusInfoBox.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.SERVICE_READY(this.migrationStateModel._sqlMigrationService!.name, this.migrationStateModel._nodeNames.join(', ')),
|
||||
style: 'success'
|
||||
});
|
||||
} else {
|
||||
this._dmsStatusInfoBox.updateProperties(<azdata.InfoBoxComponentProperties>{
|
||||
text: constants.SERVICE_NOT_READY(this.migrationStateModel._sqlMigrationService!.name),
|
||||
style: 'error'
|
||||
});
|
||||
}
|
||||
|
||||
const authenticationKeysLabel = this._view.modelBuilder.text().withProps({
|
||||
value: constants.AUTHENTICATION_KEYS,
|
||||
CSSStyles: {
|
||||
'font-weight': 'bold'
|
||||
}
|
||||
}).component();
|
||||
this._dmsStatusInfoBox.validate();
|
||||
|
||||
const migrationServiceAuthKeyTable = this._view.modelBuilder.declarativeTable().withProps({
|
||||
columns: [
|
||||
|
||||
|
||||
const data = [
|
||||
[
|
||||
{
|
||||
displayName: constants.NAME,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '50px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
'text-align': 'center'
|
||||
}
|
||||
value: constants.SERVICE_KEY1_LABEL
|
||||
},
|
||||
{
|
||||
displayName: constants.AUTH_KEY_COLUMN_HEADER,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '500px',
|
||||
isReadOnly: true,
|
||||
rowCssStyles: {
|
||||
overflow: 'scroll'
|
||||
}
|
||||
value: migrationServiceAuthKeys.authKey1
|
||||
},
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '15px',
|
||||
isReadOnly: true,
|
||||
},
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '15px',
|
||||
isReadOnly: true,
|
||||
value: this._view.modelBuilder.flexContainer().withItems([this._copy1, this._refresh1]).component()
|
||||
}
|
||||
],
|
||||
CSSStyles: {
|
||||
'margin-top': '5px'
|
||||
}
|
||||
}).component();
|
||||
|
||||
|
||||
const copyKey1Button = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.copy
|
||||
}).component();
|
||||
|
||||
copyKey1Button.onDidClick((e) => {
|
||||
vscode.env.clipboard.writeText(<string>migrationServiceAuthKeyTable.dataValues![0][1].value);
|
||||
vscode.window.showInformationMessage(constants.SERVICE_KEY_COPIED_HELP);
|
||||
});
|
||||
|
||||
const copyKey2Button = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.copy
|
||||
}).component();
|
||||
|
||||
copyKey2Button.onDidClick((e) => {
|
||||
vscode.env.clipboard.writeText(<string>migrationServiceAuthKeyTable.dataValues![1][1].value);
|
||||
vscode.window.showInformationMessage(constants.SERVICE_KEY_COPIED_HELP);
|
||||
});
|
||||
|
||||
const refreshKey1Button = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.refresh
|
||||
}).component();
|
||||
|
||||
refreshKey1Button.onDidClick((e) => {//TODO: add refresh logic
|
||||
});
|
||||
|
||||
const refreshKey2Button = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.refresh
|
||||
}).component();
|
||||
|
||||
refreshKey2Button.onDidClick((e) => {//TODO: add refresh logic
|
||||
});
|
||||
|
||||
migrationServiceAuthKeyTable.updateProperties({
|
||||
dataValues: [
|
||||
[
|
||||
{
|
||||
value: constants.SERVICE_KEY1_LABEL
|
||||
},
|
||||
{
|
||||
value: migrationServiceAuthKeys.authKey1
|
||||
},
|
||||
{
|
||||
value: copyKey1Button
|
||||
},
|
||||
{
|
||||
value: refreshKey1Button
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
value: constants.SERVICE_KEY2_LABEL
|
||||
},
|
||||
{
|
||||
value: migrationServiceAuthKeys.authKey2
|
||||
},
|
||||
{
|
||||
value: copyKey2Button
|
||||
},
|
||||
{
|
||||
value: refreshKey2Button
|
||||
}
|
||||
]
|
||||
]
|
||||
});
|
||||
|
||||
this._migrationDetailsContainer.addItems(
|
||||
[
|
||||
migrationServiceTitle,
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._targetSubscription.name),
|
||||
createInformationRow(this._view, constants.RESOURCE_GROUP, migrationService.properties.resourceGroup),
|
||||
createInformationRow(this._view, constants.LOCATION, await this.migrationStateModel.getLocationDisplayName(migrationService.location)),
|
||||
connectionLabelContainer,
|
||||
connectionStatusLoader,
|
||||
authenticationKeysLabel,
|
||||
migrationServiceAuthKeyTable
|
||||
{
|
||||
value: constants.SERVICE_KEY2_LABEL
|
||||
},
|
||||
{
|
||||
value: migrationServiceAuthKeys.authKey2
|
||||
},
|
||||
{
|
||||
value: this._view.modelBuilder.flexContainer().withItems([this._copy2, this._refresh2]).component()
|
||||
}
|
||||
]
|
||||
);
|
||||
];
|
||||
|
||||
this._authKeyTable.updateProperties({
|
||||
dataValues: data
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
this._migrationDetailsContainer.clearItems();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
} finally {
|
||||
this._statusLoadingComponent.loading = false;
|
||||
this._connectionStatusLoader.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user