From 904bf9a5dd3e35cd55327b09a6e7104a44a5d333 Mon Sep 17 00:00:00 2001 From: Ritik Kumar Date: Wed, 6 Sep 2023 13:06:27 +0530 Subject: [PATCH] [New Migration Experience] added toolbar for performance data collection (#24256) * added new icon files * updated the folder structure for skuRecommendationPage * added new toolbar for SKU Recommendation * added new toolbar for performance data collection * minors changes in data collection toolbar * removed duplicate icons/strings * updated stopDataCollection icon --- extensions/sql-migration/images/import.svg | 3 + extensions/sql-migration/images/settings.svg | 10 ++ .../images/startDataCollection.svg | 3 + .../images/stopDataCollection.svg | 3 + .../src/constants/iconPathHelper.ts | 21 +++ .../sql-migration/src/constants/strings.ts | 2 + .../sql-migration/src/constants/styles.ts | 9 +- .../assessment/assessmentResultsDialog.ts | 2 +- .../getAzureRecommendationDialog.ts | 2 +- .../skuEditParametersDialog.ts | 2 +- .../sql-migration/src/models/stateMachine.ts | 2 +- .../skuDataCollectionToolbar.ts | 127 ++++++++++++++++++ .../skuRecommendationPage.ts | 46 ++++--- .../src/wizard/wizardController.ts | 2 +- 14 files changed, 209 insertions(+), 25 deletions(-) create mode 100644 extensions/sql-migration/images/import.svg create mode 100644 extensions/sql-migration/images/settings.svg create mode 100644 extensions/sql-migration/images/startDataCollection.svg create mode 100644 extensions/sql-migration/images/stopDataCollection.svg create mode 100644 extensions/sql-migration/src/wizard/skuRecommendation/skuDataCollectionToolbar.ts rename extensions/sql-migration/src/wizard/{ => skuRecommendation}/skuRecommendationPage.ts (96%) diff --git a/extensions/sql-migration/images/import.svg b/extensions/sql-migration/images/import.svg new file mode 100644 index 000000000000..c9bb17653cd9 --- /dev/null +++ b/extensions/sql-migration/images/import.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/sql-migration/images/settings.svg b/extensions/sql-migration/images/settings.svg new file mode 100644 index 000000000000..895b2155a496 --- /dev/null +++ b/extensions/sql-migration/images/settings.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/extensions/sql-migration/images/startDataCollection.svg b/extensions/sql-migration/images/startDataCollection.svg new file mode 100644 index 000000000000..3464243804bc --- /dev/null +++ b/extensions/sql-migration/images/startDataCollection.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/sql-migration/images/stopDataCollection.svg b/extensions/sql-migration/images/stopDataCollection.svg new file mode 100644 index 000000000000..00d1ef3080ef --- /dev/null +++ b/extensions/sql-migration/images/stopDataCollection.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/sql-migration/src/constants/iconPathHelper.ts b/extensions/sql-migration/src/constants/iconPathHelper.ts index 7f6c03665a71..91f8cdf16ede 100644 --- a/extensions/sql-migration/src/constants/iconPathHelper.ts +++ b/extensions/sql-migration/src/constants/iconPathHelper.ts @@ -49,6 +49,10 @@ export class IconPathHelper { public static breadCrumb: IconPath; public static allTables: IconPath; public static notFound: IconPath; + public static startDataCollection: IconPath; + public static stopDataCollection: IconPath; + public static import: IconPath; + public static settings: IconPath; public static setExtensionContext(context: vscode.ExtensionContext) { IconPathHelper.copy = { @@ -203,5 +207,22 @@ export class IconPathHelper { light: context.asAbsolutePath('images/notFound.svg'), dark: context.asAbsolutePath('images/notFound.svg'), }; + IconPathHelper.startDataCollection = { + light: context.asAbsolutePath('images/startDataCollection.svg'), + dark: context.asAbsolutePath('images/startDataCollection.svg') + }; + IconPathHelper.stopDataCollection = { + light: context.asAbsolutePath('images/stopDataCollection.svg'), + dark: context.asAbsolutePath('images/stopDataCollection.svg') + }; + IconPathHelper.import = { + light: context.asAbsolutePath('images/import.svg'), + dark: context.asAbsolutePath('images/import.svg') + }; + IconPathHelper.settings = { + light: context.asAbsolutePath('images/settings.svg'), + dark: context.asAbsolutePath('images/settings.svg') + }; + } } diff --git a/extensions/sql-migration/src/constants/strings.ts b/extensions/sql-migration/src/constants/strings.ts index 8f5dbf27fe50..0970701ceda0 100644 --- a/extensions/sql-migration/src/constants/strings.ts +++ b/extensions/sql-migration/src/constants/strings.ts @@ -177,8 +177,10 @@ export const RECOMMENDED_CONFIGURATION = localize('sql.migration.sku.recommended export const GET_AZURE_RECOMMENDATION = localize('sql.migration.sku.get.recommendation', "Get Azure recommendation"); export const REFINE_AZURE_RECOMMENDATION = localize('sql.migration.sku.refine.recommendation', "Refine Azure recommendation"); export const REFRESH_AZURE_RECOMMENDATION = localize('sql.migration.sku.refresh.recommendation', "Refresh recommendation"); +export const START_PERFORMANCE_COLLECTION = localize('sql.migration.sku.start.performance.collection', "Start data collection"); export const STOP_PERFORMANCE_COLLECTION = localize('sql.migration.sku.stop.performance.collection', "Stop data collection"); export const RESTART_PERFORMANCE_COLLECTION = localize('sql.migration.sku.restart.performance.collection', "Restart data collection"); +export const IMPORT_PERFORMANCE_DATA = localize('sql.migration.sku.import.performance.data', "Import performance data"); // allow-any-unicode-next-line export const AZURE_RECOMMENDATION_CARD_NOT_ENABLED = localize('sql.migration.sku.card.azureRecommendation.notEnabled', "Azure recommendation is not available. Click “Get Azure recommendation” button below"); export const AZURE_RECOMMENDATION_CARD_IN_PROGRESS = localize('sql.migration.sku.card.azureRecommendation.inProgress', "Azure recommendation will be displayed once data collection is complete."); diff --git a/extensions/sql-migration/src/constants/styles.ts b/extensions/sql-migration/src/constants/styles.ts index d580273b9038..b8c998f2aae6 100644 --- a/extensions/sql-migration/src/constants/styles.ts +++ b/extensions/sql-migration/src/constants/styles.ts @@ -76,4 +76,11 @@ export const CARD_CSS = { 'padding': '8px 0px 8px 12px', 'border-radius': '4px', 'margin': '8px 0px 0px 15px' -} +}; + +export const TOOLBAR_CSS = { + 'font-size': '12px', + 'line-height': '16px', + 'font-weight': '400', + 'margin': '0', +}; \ No newline at end of file diff --git a/extensions/sql-migration/src/dialog/assessment/assessmentResultsDialog.ts b/extensions/sql-migration/src/dialog/assessment/assessmentResultsDialog.ts index b5ca43bfc326..a51127d8b41d 100644 --- a/extensions/sql-migration/src/dialog/assessment/assessmentResultsDialog.ts +++ b/extensions/sql-migration/src/dialog/assessment/assessmentResultsDialog.ts @@ -7,7 +7,7 @@ import * as azdata from 'azdata'; import * as vscode from 'vscode'; import { MigrationStateModel } from '../../models/stateMachine'; import { SqlDatabaseTree } from './sqlDatabasesTree'; -import { SKURecommendationPage } from '../../wizard/skuRecommendationPage'; +import { SKURecommendationPage } from '../../wizard/skuRecommendation/skuRecommendationPage'; import * as constants from '../../constants/strings'; import * as utils from '../../api/utils'; import { MigrationTargetType } from '../../api/utils'; diff --git a/extensions/sql-migration/src/dialog/skuRecommendationResults/getAzureRecommendationDialog.ts b/extensions/sql-migration/src/dialog/skuRecommendationResults/getAzureRecommendationDialog.ts index 83291150ac4b..1855c4375cee 100644 --- a/extensions/sql-migration/src/dialog/skuRecommendationResults/getAzureRecommendationDialog.ts +++ b/extensions/sql-migration/src/dialog/skuRecommendationResults/getAzureRecommendationDialog.ts @@ -9,7 +9,7 @@ import { MigrationStateModel, PerformanceDataSourceOptions } from '../../models/ import * as constants from '../../constants/strings'; import * as styles from '../../constants/styles'; import * as utils from '../../api/utils'; -import { SKURecommendationPage } from '../../wizard/skuRecommendationPage'; +import { SKURecommendationPage } from '../../wizard/skuRecommendation/skuRecommendationPage'; import { EOL } from 'os'; import { getSourceConnectionProfile } from '../../api/sqlUtils'; diff --git a/extensions/sql-migration/src/dialog/skuRecommendationResults/skuEditParametersDialog.ts b/extensions/sql-migration/src/dialog/skuRecommendationResults/skuEditParametersDialog.ts index c838625c7ad4..dd1b56a60233 100644 --- a/extensions/sql-migration/src/dialog/skuRecommendationResults/skuEditParametersDialog.ts +++ b/extensions/sql-migration/src/dialog/skuRecommendationResults/skuEditParametersDialog.ts @@ -9,7 +9,7 @@ import { MigrationStateModel } from '../../models/stateMachine'; import * as constants from '../../constants/strings'; import * as styles from '../../constants/styles'; import { selectDropDownIndex } from '../../api/utils'; -import { SKURecommendationPage } from '../../wizard/skuRecommendationPage'; +import { SKURecommendationPage } from '../../wizard/skuRecommendation/skuRecommendationPage'; export const TARGET_PERCENTILE_VALUES = [99, 97, 95, 90, 75, 50]; diff --git a/extensions/sql-migration/src/models/stateMachine.ts b/extensions/sql-migration/src/models/stateMachine.ts index eeac2ab91071..03586cd5db44 100644 --- a/extensions/sql-migration/src/models/stateMachine.ts +++ b/extensions/sql-migration/src/models/stateMachine.ts @@ -14,7 +14,7 @@ import * as nls from 'vscode-nls'; import { v4 as uuidv4 } from 'uuid'; import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews, logError } from '../telemetry'; import { hashString, deepClone, getBlobContainerNameWithFolder, Blob, getLastBackupFileNameWithoutFolder, MigrationTargetType } from '../api/utils'; -import { SKURecommendationPage } from '../wizard/skuRecommendationPage'; +import { SKURecommendationPage } from '../wizard/skuRecommendation/skuRecommendationPage'; import { excludeDatabases, getEncryptConnectionValue, getSourceConnectionId, getSourceConnectionProfile, getSourceConnectionServerInfo, getSourceConnectionString, getSourceConnectionUri, getTrustServerCertificateValue, SourceDatabaseInfo, TargetDatabaseInfo } from '../api/sqlUtils'; import { LoginMigrationModel } from './loginMigrationModel'; import { TdeMigrationDbResult, TdeMigrationModel } from './tdeModels'; diff --git a/extensions/sql-migration/src/wizard/skuRecommendation/skuDataCollectionToolbar.ts b/extensions/sql-migration/src/wizard/skuRecommendation/skuDataCollectionToolbar.ts new file mode 100644 index 000000000000..85314cd171b5 --- /dev/null +++ b/extensions/sql-migration/src/wizard/skuRecommendation/skuDataCollectionToolbar.ts @@ -0,0 +1,127 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------------------------- +* For Assessement Summary and SKU Recommendation Page. +* This file contains the code for toolbar at the top of page with buttons for different data +* collection functionalities. +-----------------------------------------------------------------------------------------------*/ + +import * as azdata from 'azdata'; +import * as vscode from 'vscode'; +import { IconPathHelper } from '../../constants/iconPathHelper'; +import * as styles from '../../constants/styles'; +import * as constants from '../../constants/strings'; + +export class SkuDataCollectionToolbar implements vscode.Disposable { + private _disposables: vscode.Disposable[] = []; + + public createToolbar(view: azdata.ModelView): azdata.ToolbarContainer { + const toolbar = view.modelBuilder.toolbarContainer() + + toolbar.addToolbarItems([ + { component: this.createRefreshSKURecommendationButton(view), toolbarSeparatorAfter: true }, + { component: this.createStartPerformanceCollectionButton(view), toolbarSeparatorAfter: false }, + { component: this.createStopPerformanceCollectionButton(view), toolbarSeparatorAfter: false }, + { component: this.createImportPerformanceDataButton(view), toolbarSeparatorAfter: true }, + { component: this.createRecommendationParametersButton(view), toolbarSeparatorAfter: false }, + ]); + + return toolbar.component(); + } + + private createRefreshSKURecommendationButton(view: azdata.ModelView): azdata.ButtonComponent { + const refreshSKURecommendationButton = view.modelBuilder.button() + .withProps({ + buttonType: azdata.ButtonType.Normal, + label: constants.REFRESH, + height: 36, + iconHeight: 16, + iconWidth: 16, + iconPath: IconPathHelper.refresh, + CSSStyles: { + ...styles.TOOLBAR_CSS + } + }).component(); + // TODO - implement onDidClick and add to disposables + return refreshSKURecommendationButton; + } + + private createStartPerformanceCollectionButton(view: azdata.ModelView): azdata.ButtonComponent { + const startPerformanceCollectionButton = view.modelBuilder.button() + .withProps({ + buttonType: azdata.ButtonType.Normal, + label: constants.START_PERFORMANCE_COLLECTION, + width: 146, + height: 36, + iconHeight: 16, + iconWidth: 16, + iconPath: IconPathHelper.startDataCollection, + CSSStyles: { + ...styles.TOOLBAR_CSS + } + }).component(); + // TODO - implement onDidClick and add to disposables + return startPerformanceCollectionButton; + } + + private createStopPerformanceCollectionButton(view: azdata.ModelView): azdata.ButtonComponent { + const stopPerformanceCollectionButton = view.modelBuilder.button() + .withProps({ + buttonType: azdata.ButtonType.Normal, + label: constants.STOP_PERFORMANCE_COLLECTION, + height: 36, + iconHeight: 16, + iconWidth: 16, + iconPath: IconPathHelper.stopDataCollection, + CSSStyles: { + ...styles.TOOLBAR_CSS + } + }).component(); + stopPerformanceCollectionButton.enabled = false; + // TODO - implement onDidClick and add to disposables + return stopPerformanceCollectionButton; + } + + private createImportPerformanceDataButton(view: azdata.ModelView): azdata.ButtonComponent { + const importPerformanceDataButton = view.modelBuilder.button() + .withProps({ + buttonType: azdata.ButtonType.Normal, + label: constants.IMPORT_PERFORMANCE_DATA, + height: 36, + iconHeight: 16, + iconWidth: 16, + iconPath: IconPathHelper.import, + CSSStyles: { + ...styles.TOOLBAR_CSS + } + }).component(); + // TODO - implement onDidClick and add to disposables + return importPerformanceDataButton; + } + + private createRecommendationParametersButton(view: azdata.ModelView): azdata.ButtonComponent { + const recommendationParametersButton = view.modelBuilder.button() + .withProps({ + buttonType: azdata.ButtonType.Normal, + label: constants.RECOMMENDATION_PARAMETERS, + height: 36, + iconHeight: 16, + iconWidth: 16, + iconPath: IconPathHelper.settings, + CSSStyles: { + ...styles.TOOLBAR_CSS + } + }).component(); + // TODO - implement onDidClick and add to disposables + return recommendationParametersButton; + } + + public dispose(): void { + // TODO - need to call this at the place where toolbar is initialized + this._disposables.forEach( + d => { try { d.dispose(); } catch { } }); + } +} diff --git a/extensions/sql-migration/src/wizard/skuRecommendationPage.ts b/extensions/sql-migration/src/wizard/skuRecommendation/skuRecommendationPage.ts similarity index 96% rename from extensions/sql-migration/src/wizard/skuRecommendationPage.ts rename to extensions/sql-migration/src/wizard/skuRecommendation/skuRecommendationPage.ts index a36eff08862c..7ed559dcd503 100644 --- a/extensions/sql-migration/src/wizard/skuRecommendationPage.ts +++ b/extensions/sql-migration/src/wizard/skuRecommendation/skuRecommendationPage.ts @@ -5,25 +5,26 @@ import * as azdata from 'azdata'; import * as vscode from 'vscode'; -import * as utils from '../api/utils'; -import { MigrationTargetType } from '../api/utils'; -import * as contracts from '../service/contracts'; -import { MigrationWizardPage } from '../models/migrationWizardPage'; -import { MigrationStateModel, PerformanceDataSourceOptions, StateChangeEvent, AssessmentRuleId } from '../models/stateMachine'; -import { AssessmentResultsDialog } from '../dialog/assessment/assessmentResultsDialog'; -import { SkuRecommendationResultsDialog } from '../dialog/skuRecommendationResults/skuRecommendationResultsDialog'; -import { GetAzureRecommendationDialog } from '../dialog/skuRecommendationResults/getAzureRecommendationDialog'; -import * as constants from '../constants/strings'; +import * as utils from '../../api/utils'; +import { MigrationTargetType } from '../../api/utils'; +import * as contracts from '../../service/contracts'; +import { MigrationWizardPage } from '../../models/migrationWizardPage'; +import { MigrationStateModel, PerformanceDataSourceOptions, StateChangeEvent, AssessmentRuleId } from '../../models/stateMachine'; +import { AssessmentResultsDialog } from '../../dialog/assessment/assessmentResultsDialog'; +import { SkuRecommendationResultsDialog } from '../../dialog/skuRecommendationResults/skuRecommendationResultsDialog'; +import { GetAzureRecommendationDialog } from '../../dialog/skuRecommendationResults/getAzureRecommendationDialog'; +import * as constants from '../../constants/strings'; import { EOL } from 'os'; -import { IconPath, IconPathHelper } from '../constants/iconPathHelper'; -import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController'; -import * as styles from '../constants/styles'; -import { SkuEditParametersDialog } from '../dialog/skuRecommendationResults/skuEditParametersDialog'; -import { logError, TelemetryViews, TelemetryAction, sendSqlMigrationActionEvent, getTelemetryProps } from '../telemetry'; -import { TdeConfigurationDialog } from '../dialog/tdeConfiguration/tdeConfigurationDialog'; -import { TdeMigrationModel } from '../models/tdeModels'; -import { getSourceConnectionProfile } from '../api/sqlUtils'; -import { ConfigDialogSetting } from '../models/tdeModels' +import { IconPath, IconPathHelper } from '../../constants/iconPathHelper'; +import { WIZARD_INPUT_COMPONENT_WIDTH } from '../wizardController'; +import * as styles from '../../constants/styles'; +import { SkuEditParametersDialog } from '../../dialog/skuRecommendationResults/skuEditParametersDialog'; +import { logError, TelemetryViews, TelemetryAction, sendSqlMigrationActionEvent, getTelemetryProps } from '../../telemetry'; +import { TdeConfigurationDialog } from '../../dialog/tdeConfiguration/tdeConfigurationDialog'; +import { TdeMigrationModel } from '../../models/tdeModels'; +import { getSourceConnectionProfile } from '../../api/sqlUtils'; +import { ConfigDialogSetting } from '../../models/tdeModels'; +import { SkuDataCollectionToolbar } from './skuDataCollectionToolbar'; export interface Product { type: MigrationTargetType; @@ -59,6 +60,7 @@ export class SKURecommendationPage extends MigrationWizardPage { private _azureRecommendationInfoText!: azdata.TextComponent; private _getAzureRecommendationButton!: azdata.ButtonComponent; + private _skuDataCollectionToolbar!: SkuDataCollectionToolbar; private _skuDataCollectionStatusContainer!: azdata.FlexContainer; private _skuDataCollectionStatusIcon!: azdata.ImageComponent; private _skuDataCollectionStatusText!: azdata.TextComponent; @@ -118,6 +120,12 @@ export class SKURecommendationPage extends MigrationWizardPage { width: 20, height: 20 }).component(); + + this._skuDataCollectionToolbar = new SkuDataCollectionToolbar(); + const toolbar = this._skuDataCollectionToolbar.createToolbar(view); + // TODO - add toolbar to disposables + // TODO - once new toolbar is ready for data collection, remove previous code. + const igContainer = this._view.modelBuilder.flexContainer() .withProps({ CSSStyles: { 'align-items': 'center' } }) .component(); @@ -172,6 +180,7 @@ export class SKURecommendationPage extends MigrationWizardPage { const statusContainer = this._view.modelBuilder.flexContainer() .withLayout({ flexFlow: 'column' }) .withItems([ + toolbar, igContainer, this._detailsComponent, refreshAssessmentButton, @@ -219,7 +228,6 @@ export class SKURecommendationPage extends MigrationWizardPage { await this._view.initializeModel(this._rootContainer); } - private createStatusComponent(view: azdata.ModelView): azdata.TextComponent { const component = view.modelBuilder.text() .withProps({ diff --git a/extensions/sql-migration/src/wizard/wizardController.ts b/extensions/sql-migration/src/wizard/wizardController.ts index 921fcf56023f..657029ac58ee 100644 --- a/extensions/sql-migration/src/wizard/wizardController.ts +++ b/extensions/sql-migration/src/wizard/wizardController.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import { MigrationStateModel, NetworkContainerType, Page } from '../models/stateMachine'; import * as loc from '../constants/strings'; import { MigrationWizardPage } from '../models/migrationWizardPage'; -import { SKURecommendationPage } from './skuRecommendationPage'; +import { SKURecommendationPage } from './skuRecommendation/skuRecommendationPage'; import { DatabaseBackupPage } from './databaseBackupPage'; import { TargetSelectionPage } from './targetSelectionPage'; import { LoginMigrationTargetSelectionPage } from './loginMigrationTargetSelectionPage';