mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-01 09:35:41 -05:00
SQL-Migration: improve SQL DB table selection ux to include missing tables (#22659)
* add missing target tables ux * fix number formatting
This commit is contained in:
@@ -807,7 +807,9 @@ export function sortResourceArrayByName(resourceArray: SortableAzureResources[])
|
||||
export function getMigrationTargetId(migration: DatabaseMigration): string {
|
||||
// `${targetServerId}/providers/Microsoft.DataMigration/databaseMigrations/${targetDatabaseName}?api-version=${DMSV2_API_VERSION}`
|
||||
const paths = migration.id.split('/providers/Microsoft.DataMigration/', 1);
|
||||
return paths[0];
|
||||
return paths?.length > 0
|
||||
? paths[0]
|
||||
: '';
|
||||
}
|
||||
|
||||
export function getMigrationTargetName(migration: DatabaseMigration): string {
|
||||
|
||||
@@ -667,21 +667,24 @@ export const SELECT_RESOURCE_GROUP_PROMPT = localize('sql.migration.blob.resourc
|
||||
export const SELECT_STORAGE_ACCOUNT = localize('sql.migration.blob.storageAccount.select', "Select a storage account value first.");
|
||||
export const SELECT_BLOB_CONTAINER = localize('sql.migration.blob.container.select', "Select a blob container value first.");
|
||||
|
||||
|
||||
export const MISSING_TABLE_NAME_COLUMN = localize('sql.migration.missing.table.name.column', "Table name");
|
||||
export function SELECT_DATABASE_TABLES_TITLE(targetDatabaseName: string): string {
|
||||
return localize('sql.migration.table.select.label', "Select tables for {0}", targetDatabaseName);
|
||||
}
|
||||
export const TABLE_SELECTION_EDIT = localize('sql.migration.table.selection.edit', "Edit");
|
||||
|
||||
export function TABLE_SELECTION_COUNT(selectedCount: number, rowCount: number): string {
|
||||
return localize('sql.migration.table.selection.count', "{0} of {1}", selectedCount, rowCount);
|
||||
return localize('sql.migration.table.selection.count', "{0} of {1}", formatNumber(selectedCount), formatNumber(rowCount));
|
||||
}
|
||||
export function TABLE_SELECTED_COUNT(selectedCount: number, rowCount: number): string {
|
||||
return localize('sql.migration.table.selected.count', "{0} of {1} tables selected", selectedCount, rowCount);
|
||||
return localize('sql.migration.table.selected.count', "{0} of {1} tables selected", formatNumber(selectedCount), formatNumber(rowCount));
|
||||
}
|
||||
export function MISSING_TARGET_TABLES_COUNT(tables: number): string {
|
||||
return localize('sql.migration.table.missing.count', "Missing target tables excluded from list: {0}", tables);
|
||||
return localize('sql.migration.table.missing.count', "Tables missing on target: {0}", formatNumber(tables));
|
||||
}
|
||||
export const DATABASE_MISSING_TABLES = localize('sql.migration.database.missing.tables', "0 tables found.");
|
||||
export const SELECT_TABLES_FOR_MIGRATION = localize('sql.migration.select.migration.tables', "Select tables for migration");
|
||||
export const DATABASE_MISSING_TABLES = localize('sql.migration.database.missing.tables', "0 tables found on source database.");
|
||||
export const DATABASE_LOADING_TABLES = localize('sql.migration.database.loading.tables', "Loading tables list...");
|
||||
export const TABLE_SELECTION_FILTER = localize('sql.migration.table.selection.filter', "Filter tables");
|
||||
export const TABLE_SELECTION_UPDATE_BUTTON = localize('sql.migration.table.selection.update.button', "Update");
|
||||
@@ -932,7 +935,9 @@ export const AZURE_STORAGE_ACCOUNT_TO_UPLOAD_BACKUPS = localize('sql.migration.a
|
||||
export const SHIR = localize('sql.migration.shir', "Self-hosted integration runtime node");
|
||||
export const DATABASE_TO_BE_MIGRATED = localize('sql.migration.database.to.be.migrated', "Database to be migrated");
|
||||
export function COUNT_DATABASES(count: number): string {
|
||||
return (count === 1) ? localize('sql.migration.count.database.single', "{0} database", count) : localize('sql.migration.count.database.multiple', "{0} databases", count);
|
||||
return (count === 1)
|
||||
? localize('sql.migration.count.database.single', "{0} database", count)
|
||||
: localize('sql.migration.count.database.multiple', "{0} databases", formatNumber(count));
|
||||
}
|
||||
export function TOTAL_TABLES_SELECTED(selected: number, total: number): string {
|
||||
return localize('total.tables.selected.of.total', "{0} of {1}", formatNumber(selected), formatNumber(total));
|
||||
|
||||
@@ -401,7 +401,11 @@ export class CreateSqlMigrationServiceDialog {
|
||||
constants.RESOURCE_GROUP_NOT_FOUND);
|
||||
|
||||
const selectedResourceGroupValue = this.migrationServiceResourceGroupDropdown.values.find(v => v.name.toLowerCase() === this._resourceGroupPreset.toLowerCase());
|
||||
this.migrationServiceResourceGroupDropdown.value = (selectedResourceGroupValue) ? selectedResourceGroupValue : this.migrationServiceResourceGroupDropdown.values[0];
|
||||
this.migrationServiceResourceGroupDropdown.value = (selectedResourceGroupValue)
|
||||
? selectedResourceGroupValue
|
||||
: this.migrationServiceResourceGroupDropdown.values?.length > 0
|
||||
? this.migrationServiceResourceGroupDropdown.values[0]
|
||||
: '';
|
||||
} finally {
|
||||
this.migrationServiceResourceGroupDropdown.loading = false;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import * as constants from '../../constants/strings';
|
||||
import { AzureSqlDatabaseServer } from '../../api/azure';
|
||||
import { collectSourceDatabaseTableInfo, collectTargetDatabaseTableInfo, TableInfo } from '../../api/sqlUtils';
|
||||
import { MigrationStateModel } from '../../models/stateMachine';
|
||||
import { IconPathHelper } from '../../constants/iconPathHelper';
|
||||
import { Tab } from 'azdata';
|
||||
import { updateControlDisplay } from '../../api/utils';
|
||||
|
||||
const DialogName = 'TableMigrationSelection';
|
||||
@@ -16,10 +18,11 @@ const DialogName = 'TableMigrationSelection';
|
||||
export class TableMigrationSelectionDialog {
|
||||
private _dialog: azdata.window.Dialog | undefined;
|
||||
private _headingText!: azdata.TextComponent;
|
||||
private _missingTablesText!: azdata.TextComponent;
|
||||
private _refreshButton!: azdata.ButtonComponent;
|
||||
private _filterInputBox!: azdata.InputBoxComponent;
|
||||
private _tableSelectionTable!: azdata.TableComponent;
|
||||
private _tableLoader!: azdata.LoadingComponent;
|
||||
private _missingTargetTablesTable!: azdata.TableComponent;
|
||||
private _refreshLoader!: azdata.LoadingComponent;
|
||||
private _disposables: vscode.Disposable[] = [];
|
||||
private _isOpen: boolean = false;
|
||||
private _model: MigrationStateModel;
|
||||
@@ -28,6 +31,9 @@ export class TableMigrationSelectionDialog {
|
||||
private _targetTableMap!: Map<string, TableInfo>;
|
||||
private _onSaveCallback: () => Promise<void>;
|
||||
private _missingTableCount: number = 0;
|
||||
private _selectableTablesTab!: Tab;
|
||||
private _missingTablesTab!: Tab;
|
||||
private _tabs!: azdata.TabbedPanelComponent;
|
||||
|
||||
constructor(
|
||||
model: MigrationStateModel,
|
||||
@@ -41,7 +47,12 @@ export class TableMigrationSelectionDialog {
|
||||
|
||||
private async _loadData(): Promise<void> {
|
||||
try {
|
||||
this._tableLoader.loading = true;
|
||||
this._refreshLoader.loading = true;
|
||||
|
||||
this._updateRowSelection();
|
||||
await updateControlDisplay(this._tableSelectionTable, false);
|
||||
await updateControlDisplay(this._missingTargetTablesTable, false);
|
||||
|
||||
const targetDatabaseInfo = this._model._sourceTargetMapping.get(this._sourceDatabaseName);
|
||||
if (targetDatabaseInfo) {
|
||||
const sourceTableList: TableInfo[] = await collectSourceDatabaseTableInfo(
|
||||
@@ -86,6 +97,7 @@ export class TableMigrationSelectionDialog {
|
||||
this._tableSelectionMap.set(table.tableName, tableInfo);
|
||||
});
|
||||
}
|
||||
this._dialog!.message = { text: '', level: azdata.window.MessageLevel.Information };
|
||||
} catch (error) {
|
||||
this._dialog!.message = {
|
||||
text: constants.DATABASE_TABLE_CONNECTION_ERROR,
|
||||
@@ -93,13 +105,16 @@ export class TableMigrationSelectionDialog {
|
||||
level: azdata.window.MessageLevel.Error
|
||||
};
|
||||
} finally {
|
||||
this._tableLoader.loading = false;
|
||||
this._refreshLoader.loading = false;
|
||||
await updateControlDisplay(this._tableSelectionTable, true, 'flex');
|
||||
await updateControlDisplay(this._missingTargetTablesTable, true, 'flex');
|
||||
await this._loadControls();
|
||||
}
|
||||
}
|
||||
|
||||
private async _loadControls(): Promise<void> {
|
||||
const data: any[][] = [];
|
||||
const missingData: any[][] = [];
|
||||
const filterText = this._filterInputBox.value ?? '';
|
||||
const selectedItems: number[] = [];
|
||||
let tableRow = 0;
|
||||
@@ -125,67 +140,45 @@ export class TableMigrationSelectionDialog {
|
||||
}
|
||||
|
||||
tableRow++;
|
||||
} else {
|
||||
this._missingTableCount++;
|
||||
missingData.push([sourceTable.tableName]);
|
||||
}
|
||||
|
||||
this._missingTableCount += targetTable ? 0 : 1;
|
||||
}
|
||||
});
|
||||
await this._tableSelectionTable.updateProperty('data', data);
|
||||
this._tableSelectionTable.selectedRows = selectedItems;
|
||||
await this._updateRowSelection();
|
||||
await this._missingTargetTablesTable.updateProperty('data', missingData);
|
||||
|
||||
this._updateRowSelection();
|
||||
if (this._missingTableCount > 0 && this._tabs.items.length === 1) {
|
||||
this._tabs.updateTabs([this._selectableTablesTab, this._missingTablesTab]);
|
||||
}
|
||||
}
|
||||
|
||||
private async _initializeDialog(dialog: azdata.window.Dialog): Promise<void> {
|
||||
dialog.registerContent(async (view) => {
|
||||
this._filterInputBox = view.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
inputType: 'search',
|
||||
placeHolder: constants.TABLE_SELECTION_FILTER,
|
||||
width: 268,
|
||||
}).component();
|
||||
const tab = azdata.window.createTab('');
|
||||
tab.registerContent(async (view) => {
|
||||
|
||||
this._disposables.push(
|
||||
this._filterInputBox.onTextChanged(
|
||||
async e => await this._loadControls()));
|
||||
|
||||
this._headingText = view.modelBuilder.text()
|
||||
.withProps({ value: constants.DATABASE_LOADING_TABLES })
|
||||
this._tabs = view.modelBuilder.tabbedPanel()
|
||||
.withTabs([])
|
||||
.component();
|
||||
|
||||
this._missingTablesText = view.modelBuilder.text()
|
||||
.withProps({ display: 'none' })
|
||||
.component();
|
||||
await this._createSelectableTablesTab(view);
|
||||
await this._createMissingTablesTab(view);
|
||||
|
||||
this._tableSelectionTable = await this._createSelectionTable(view);
|
||||
this._tableLoader = view.modelBuilder.loadingComponent()
|
||||
.withItem(this._tableSelectionTable)
|
||||
.withProps({
|
||||
loading: false,
|
||||
loadingText: constants.DATABASE_TABLE_DATA_LOADING
|
||||
}).component();
|
||||
|
||||
const flex = view.modelBuilder.flexContainer()
|
||||
.withItems([
|
||||
this._filterInputBox,
|
||||
this._headingText,
|
||||
this._missingTablesText,
|
||||
this._tableLoader],
|
||||
{ flex: '0 0 auto' })
|
||||
.withProps({ CSSStyles: { 'margin': '0 0 0 15px' } })
|
||||
.withLayout({
|
||||
flexFlow: 'column',
|
||||
height: '100%',
|
||||
width: 565,
|
||||
}).component();
|
||||
this._tabs.updateTabs([this._selectableTablesTab]);
|
||||
|
||||
this._disposables.push(
|
||||
view.onClosed(e =>
|
||||
this._disposables.forEach(
|
||||
d => { try { d.dispose(); } catch { } })));
|
||||
|
||||
await view.initializeModel(flex);
|
||||
await view.initializeModel(this._tabs);
|
||||
await this._loadData();
|
||||
});
|
||||
|
||||
dialog.content = [tab];
|
||||
}
|
||||
|
||||
public async openDialog(dialogTitle: string) {
|
||||
@@ -194,7 +187,7 @@ export class TableMigrationSelectionDialog {
|
||||
this._dialog = azdata.window.createModelViewDialog(
|
||||
dialogTitle,
|
||||
DialogName,
|
||||
600);
|
||||
600, undefined, undefined, false);
|
||||
|
||||
this._dialog.okButton.label = constants.TABLE_SELECTION_UPDATE_BUTTON;
|
||||
this._dialog.okButton.position = 'left';
|
||||
@@ -214,13 +207,105 @@ export class TableMigrationSelectionDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private async _createSelectionTable(view: azdata.ModelView): Promise<azdata.TableComponent> {
|
||||
private async _createSelectableTablesTab(view: azdata.ModelView): Promise<void> {
|
||||
this._headingText = view.modelBuilder.text()
|
||||
.withProps({ value: constants.DATABASE_LOADING_TABLES })
|
||||
.component();
|
||||
|
||||
this._filterInputBox = view.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
inputType: 'search',
|
||||
placeHolder: constants.TABLE_SELECTION_FILTER,
|
||||
width: 268,
|
||||
}).component();
|
||||
|
||||
this._disposables.push(
|
||||
this._filterInputBox.onTextChanged(
|
||||
async e => await this._loadControls()));
|
||||
|
||||
this._refreshButton = view.modelBuilder.button()
|
||||
.withProps({
|
||||
buttonType: azdata.ButtonType.Normal,
|
||||
iconHeight: 16,
|
||||
iconWidth: 16,
|
||||
iconPath: IconPathHelper.refresh,
|
||||
label: constants.DATABASE_TABLE_REFRESH_LABEL,
|
||||
width: 70,
|
||||
CSSStyles: { 'margin': '5px 0 0 15px' },
|
||||
})
|
||||
.component();
|
||||
this._disposables.push(
|
||||
this._refreshButton.onDidClick(
|
||||
async e => await this._loadData()));
|
||||
|
||||
this._refreshLoader = view.modelBuilder.loadingComponent()
|
||||
.withItem(this._refreshButton)
|
||||
.withProps({
|
||||
loading: false,
|
||||
CSSStyles: { 'height': '8px', 'margin': '5px 0 0 15px' }
|
||||
})
|
||||
.component();
|
||||
|
||||
const flexTopRow = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
flexWrap: 'wrap',
|
||||
})
|
||||
.component();
|
||||
flexTopRow.addItem(this._filterInputBox, { flex: '0 0 auto' });
|
||||
flexTopRow.addItem(this._refreshLoader, { flex: '0 0 auto' });
|
||||
|
||||
this._tableSelectionTable = this._createSelectionTable(view);
|
||||
|
||||
const flex = view.modelBuilder.flexContainer()
|
||||
.withItems([
|
||||
flexTopRow,
|
||||
this._headingText,
|
||||
this._tableSelectionTable],
|
||||
{ flex: '0 0 auto' })
|
||||
.withProps({ CSSStyles: { 'margin': '10px 0 0 15px' } })
|
||||
.withLayout({
|
||||
flexFlow: 'column',
|
||||
height: '100%',
|
||||
width: 550,
|
||||
}).component();
|
||||
|
||||
this._selectableTablesTab = {
|
||||
content: flex,
|
||||
id: 'tableSelectionTab',
|
||||
title: constants.SELECT_TABLES_FOR_MIGRATION,
|
||||
};
|
||||
}
|
||||
|
||||
private async _createMissingTablesTab(view: azdata.ModelView): Promise<void> {
|
||||
this._missingTargetTablesTable = this._createMissingTablesTable(view);
|
||||
|
||||
const flex = view.modelBuilder.flexContainer()
|
||||
.withItems(
|
||||
[this._missingTargetTablesTable],
|
||||
{ flex: '0 0 auto' })
|
||||
.withProps({ CSSStyles: { 'margin': '10px 0 0 15px' } })
|
||||
.withLayout({
|
||||
flexFlow: 'column',
|
||||
height: '100%',
|
||||
width: 550,
|
||||
}).component();
|
||||
|
||||
this._missingTablesTab = {
|
||||
content: flex,
|
||||
id: 'missingTablesTab',
|
||||
title: constants.MISSING_TARGET_TABLES_COUNT(this._missingTableCount),
|
||||
};
|
||||
}
|
||||
|
||||
private _createSelectionTable(view: azdata.ModelView): azdata.TableComponent {
|
||||
const cssClass = 'no-borders';
|
||||
const table = view.modelBuilder.table()
|
||||
.withProps({
|
||||
data: [],
|
||||
width: 565,
|
||||
width: 550,
|
||||
height: '600px',
|
||||
display: 'flex',
|
||||
forceFitColumns: azdata.ColumnSizingMode.ForceFit,
|
||||
columns: [
|
||||
<azdata.CheckboxColumn>{
|
||||
@@ -236,7 +321,7 @@ export class TableMigrationSelectionDialog {
|
||||
name: constants.TABLE_SELECTION_TABLENAME_COLUMN,
|
||||
value: 'tableName',
|
||||
type: azdata.ColumnType.text,
|
||||
width: 300,
|
||||
width: 285,
|
||||
cssClass: cssClass,
|
||||
headerCssClass: cssClass,
|
||||
},
|
||||
@@ -275,23 +360,45 @@ export class TableMigrationSelectionDialog {
|
||||
}
|
||||
});
|
||||
|
||||
await this._updateRowSelection();
|
||||
this._updateRowSelection();
|
||||
}));
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
private async _updateRowSelection(): Promise<void> {
|
||||
this._headingText.value = this._tableSelectionTable.data.length > 0
|
||||
? constants.TABLE_SELECTED_COUNT(
|
||||
this._tableSelectionTable.selectedRows?.length ?? 0,
|
||||
this._tableSelectionTable.data.length)
|
||||
: this._tableLoader.loading
|
||||
? constants.DATABASE_LOADING_TABLES
|
||||
private _createMissingTablesTable(view: azdata.ModelView): azdata.TableComponent {
|
||||
const cssClass = 'no-borders';
|
||||
const table = view.modelBuilder.table()
|
||||
.withProps({
|
||||
data: [],
|
||||
width: 550,
|
||||
height: '600px',
|
||||
display: 'flex',
|
||||
forceFitColumns: azdata.ColumnSizingMode.ForceFit,
|
||||
columns: [{
|
||||
name: constants.MISSING_TABLE_NAME_COLUMN,
|
||||
value: 'tableName',
|
||||
type: azdata.ColumnType.text,
|
||||
cssClass: cssClass,
|
||||
headerCssClass: cssClass,
|
||||
}],
|
||||
})
|
||||
.withValidation(() => true)
|
||||
.component();
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
private _updateRowSelection(): void {
|
||||
this._headingText.value = this._refreshLoader.loading
|
||||
? constants.DATABASE_LOADING_TABLES
|
||||
: this._tableSelectionTable.data?.length > 0
|
||||
? constants.TABLE_SELECTED_COUNT(
|
||||
this._tableSelectionTable.selectedRows?.length ?? 0,
|
||||
this._tableSelectionTable.data?.length ?? 0)
|
||||
: constants.DATABASE_MISSING_TABLES;
|
||||
|
||||
this._missingTablesText.value = constants.MISSING_TARGET_TABLES_COUNT(this._missingTableCount);
|
||||
await updateControlDisplay(this._missingTablesText, this._missingTableCount > 0);
|
||||
this._missingTablesTab.title = constants.MISSING_TARGET_TABLES_COUNT(this._missingTableCount);
|
||||
}
|
||||
|
||||
private async _save(): Promise<void> {
|
||||
@@ -303,7 +410,7 @@ export class TableMigrationSelectionDialog {
|
||||
selectedRows.forEach(rowIndex => {
|
||||
const tableRow = this._tableSelectionTable.data[rowIndex];
|
||||
const tableName = tableRow.length > 1
|
||||
? this._tableSelectionTable.data[rowIndex][1] as string
|
||||
? tableRow[1] as string
|
||||
: '';
|
||||
const tableInfo = this._tableSelectionMap.get(tableName);
|
||||
if (tableInfo) {
|
||||
|
||||
@@ -97,12 +97,15 @@ export function sendSqlMigrationActionEvent(telemetryView: TelemetryViews, telem
|
||||
}
|
||||
|
||||
export function getTelemetryProps(migrationStateModel: MigrationStateModel): TelemetryEventProperties {
|
||||
const tenantId = migrationStateModel._azureAccount?.properties?.tenants?.length > 0
|
||||
? migrationStateModel._azureAccount?.properties?.tenants[0]?.id
|
||||
: '';
|
||||
return {
|
||||
'sessionId': migrationStateModel._sessionId,
|
||||
'subscriptionId': migrationStateModel._targetSubscription?.id,
|
||||
'resourceGroup': migrationStateModel._resourceGroup?.name,
|
||||
'targetType': migrationStateModel._targetType,
|
||||
'tenantId': migrationStateModel._azureAccount?.properties?.tenants[0]?.id,
|
||||
'tenantId': tenantId,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -897,14 +897,16 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
this._sqlSourceUsernameInput.value = username;
|
||||
this._sqlSourcePassword.value = (await getSourceConnectionCredentials()).password;
|
||||
|
||||
this._windowsUserAccountText.value =
|
||||
this.migrationStateModel._databaseBackup.networkShares[0]?.windowsUser
|
||||
?? this.migrationStateModel.savedInfo?.networkShares[0]?.windowsUser
|
||||
?? '';
|
||||
this._passwordText.value =
|
||||
this.migrationStateModel._databaseBackup.networkShares[0]?.password
|
||||
?? this.migrationStateModel.savedInfo?.networkShares[0]?.password
|
||||
?? '';
|
||||
const networkShares = this.migrationStateModel._databaseBackup?.networkShares?.length > 0
|
||||
? this.migrationStateModel._databaseBackup?.networkShares
|
||||
: this.migrationStateModel.savedInfo?.networkShares ?? [];
|
||||
|
||||
const networkShare = networkShares?.length > 0
|
||||
? networkShares[0]
|
||||
: undefined;
|
||||
|
||||
this._windowsUserAccountText.value = networkShare?.windowsUser ?? '';
|
||||
this._passwordText.value = networkShare?.password ?? '';
|
||||
|
||||
this._networkShareTargetDatabaseNames = [];
|
||||
this._networkShareLocations = [];
|
||||
@@ -1379,13 +1381,15 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
break;
|
||||
case NetworkContainerType.NETWORK_SHARE:
|
||||
// All network share migrations use the same storage account
|
||||
const storageAccount = this.migrationStateModel._databaseBackup.networkShares[0]?.storageAccount;
|
||||
const storageKey = (await getStorageAccountAccessKeys(
|
||||
this.migrationStateModel._azureAccount,
|
||||
this.migrationStateModel._databaseBackup.subscription,
|
||||
storageAccount)).keyName1;
|
||||
for (let i = 0; i < this.migrationStateModel._databaseBackup.networkShares.length; i++) {
|
||||
this.migrationStateModel._databaseBackup.networkShares[i].storageKey = storageKey;
|
||||
if (this.migrationStateModel._databaseBackup.networkShares?.length > 0) {
|
||||
const storageAccount = this.migrationStateModel._databaseBackup.networkShares[0]?.storageAccount;
|
||||
const storageKey = (await getStorageAccountAccessKeys(
|
||||
this.migrationStateModel._azureAccount,
|
||||
this.migrationStateModel._databaseBackup.subscription,
|
||||
storageAccount)).keyName1;
|
||||
for (let i = 0; i < this.migrationStateModel._databaseBackup.networkShares.length; i++) {
|
||||
this.migrationStateModel._databaseBackup.networkShares[i].storageKey = storageKey;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationMode, MigrationStateModel, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
|
||||
import { MigrationMode, MigrationStateModel, NetworkContainerType, NetworkShare, StateChangeEvent } from '../models/stateMachine';
|
||||
import * as constants from '../constants/strings';
|
||||
import { createHeadingTextComponent, createInformationRow, createLabelTextComponent } from './wizardController';
|
||||
import { getResourceGroupFromId } from '../api/azure';
|
||||
@@ -185,7 +185,10 @@ export class SummaryPage extends MigrationWizardPage {
|
||||
.withLayout({ flexFlow: 'column' })
|
||||
.component();
|
||||
|
||||
const networkShare = this.migrationStateModel._databaseBackup.networkShares[0];
|
||||
const networkShare = this.migrationStateModel._databaseBackup.networkShares?.length > 0
|
||||
? this.migrationStateModel._databaseBackup.networkShares[0]
|
||||
: <NetworkShare>{};
|
||||
|
||||
switch (this.migrationStateModel._databaseBackup.networkContainerType) {
|
||||
case NetworkContainerType.NETWORK_SHARE:
|
||||
flexContainer.addItems([
|
||||
|
||||
Reference in New Issue
Block a user