diff --git a/src/sql/platform/telemetry/common/telemetryKeys.ts b/src/sql/platform/telemetry/common/telemetryKeys.ts index 0b77fbc0cb..ee59b4eac8 100644 --- a/src/sql/platform/telemetry/common/telemetryKeys.ts +++ b/src/sql/platform/telemetry/common/telemetryKeys.ts @@ -38,6 +38,7 @@ export const enum TelemetryView { AgentNotebookHistory = 'AgentNotebookHistory', AgentNotebooks = 'AgentNotebooks', ConnectionDialog = 'ConnectionDialog', + ExecutionPlan = 'ExecutionPlan', ExtensionHost = 'ExtensionHost', ExtensionRecommendationDialog = 'ExtensionRecommendationDialog', Notebook = 'Notebook', @@ -55,6 +56,7 @@ export const enum TelemetryAction { AddServerGroup = 'AddServerGroup', adsCommandExecuted = 'adsCommandExecuted', ConnectToServer = 'ConnectToServer', + CustomZoom = 'CustomZoom', BackupCreated = 'BackupCreated', DashboardNavigated = 'DashboardNavigated', DatabaseConnected = 'DatabaseConnected', @@ -69,6 +71,7 @@ export const enum TelemetryAction { CancelQuery = 'CancelQuery', ChartCreated = 'ChartCreated', Click = 'Click', + FindNode = 'FindNode', FirewallRuleRequested = 'FirewallRuleCreated', GenerateScript = 'GenerateScript', GeneratePreviewReport = 'GeneratePreviewReport', @@ -82,6 +85,8 @@ export const enum TelemetryAction { NewQuery = 'NewQuery', ObjectExplorerExpand = 'ObjectExplorerExpand', Open = 'Open', + OpenQuery = 'OpenQuery', + OpenExecutionPlanProperties = 'OpenExecutionPlanProperties', PublishChanges = 'PublishChanges', RestoreRequested = 'RestoreRequested', RunAgentJob = 'RunAgentJob', @@ -90,9 +95,13 @@ export const enum TelemetryAction { RunQueryString = 'RunQueryString', ShowChart = 'ShowChart', StopAgentJob = 'StopAgentJob', + ViewTopOperations = 'ViewTopOperations', WizardPagesNavigation = 'WizardPagesNavigation', SearchStarted = 'SearchStarted', - SearchCompleted = 'SearchCompleted' + SearchCompleted = 'SearchCompleted', + ZoomIn = 'ZoomIn', + ZoomOut = 'ZoomOut', + ZoomToFit = 'ZoomToFIt' } export const enum NbTelemetryAction { diff --git a/src/sql/workbench/contrib/executionPlan/browser/executionPlanView.ts b/src/sql/workbench/contrib/executionPlan/browser/executionPlanView.ts index 2b230e62d1..99bbc548fd 100644 --- a/src/sql/workbench/contrib/executionPlan/browser/executionPlanView.ts +++ b/src/sql/workbench/contrib/executionPlan/browser/executionPlanView.ts @@ -33,6 +33,8 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { CustomZoomWidget } from 'sql/workbench/contrib/executionPlan/browser/widgets/customZoomWidget'; import { NodeSearchWidget } from 'sql/workbench/contrib/executionPlan/browser/widgets/nodeSearchWidget'; import { AzdataGraphView } from 'sql/workbench/contrib/executionPlan/browser/azdataGraphView'; +import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry'; +import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys'; export class ExecutionPlanView implements ISashLayoutProvider { @@ -153,13 +155,13 @@ export class ExecutionPlanView implements ISashLayoutProvider { const actionBarActions = [ new SavePlanFile(), new OpenPlanFile(), - new OpenQueryAction(), - new SearchNodeAction(), - new ZoomInAction(), - new ZoomOutAction(), - new ZoomToFitAction(), - new CustomZoomAction(), - new PropertiesAction(), + this._instantiationService.createInstance(OpenQueryAction, 'ActionBar'), + this._instantiationService.createInstance(SearchNodeAction, 'ActionBar'), + this._instantiationService.createInstance(ZoomInAction, 'ActionBar'), + this._instantiationService.createInstance(ZoomOutAction, 'ActionBar'), + this._instantiationService.createInstance(ZoomToFitAction, 'ActionBar'), + this._instantiationService.createInstance(CustomZoomAction, 'ActionBar'), + this._instantiationService.createInstance(PropertiesAction, 'ActionBar'), this.actionBarToggleTopTip ]; this._actionBar.pushAction(actionBarActions, { icon: true, label: false }); @@ -169,13 +171,13 @@ export class ExecutionPlanView implements ISashLayoutProvider { const contextMenuAction = [ new SavePlanFile(), new OpenPlanFile(), - new OpenQueryAction(), - new SearchNodeAction(), - new ZoomInAction(), - new ZoomOutAction(), - new ZoomToFitAction(), - new CustomZoomAction(), - new PropertiesAction(), + this._instantiationService.createInstance(OpenQueryAction, 'ContextMenu'), + this._instantiationService.createInstance(SearchNodeAction, 'ContextMenu'), + this._instantiationService.createInstance(ZoomInAction, 'ContextMenu'), + this._instantiationService.createInstance(ZoomOutAction, 'ContextMenu'), + this._instantiationService.createInstance(ZoomToFitAction, 'ContextMenu'), + this._instantiationService.createInstance(CustomZoomAction, 'ContextMenu'), + this._instantiationService.createInstance(PropertiesAction, 'ContextMenu'), this.contextMenuToggleTooltipAction ]; const self = this; @@ -269,15 +271,24 @@ export class ExecutionPlanView implements ISashLayoutProvider { } } +type ExecutionPlanActionSource = 'ContextMenu' | 'ActionBar'; + export class OpenQueryAction extends Action { public static ID = 'ep.OpenQueryAction'; public static LABEL = localize('openQueryAction', "Open Query"); - constructor() { + constructor(private source: ExecutionPlanActionSource, + @IAdsTelemetryService private readonly telemetryService: IAdsTelemetryService + ) { super(OpenQueryAction.ID, OpenQueryAction.LABEL, openQueryIconClassNames); } public override async run(context: ExecutionPlanView): Promise { + this.telemetryService + .createActionEvent(TelemetryKeys.TelemetryView.ExecutionPlan, TelemetryKeys.TelemetryAction.OpenQuery) + .withAdditionalProperties({ source: this.source }) + .send(); + context.openQuery(); } } @@ -286,11 +297,18 @@ export class PropertiesAction extends Action { public static ID = 'ep.propertiesAction'; public static LABEL = localize('executionPlanPropertiesActionLabel', "Properties"); - constructor() { + constructor(private source: ExecutionPlanActionSource, + @IAdsTelemetryService private readonly telemetryService: IAdsTelemetryService + ) { super(PropertiesAction.ID, PropertiesAction.LABEL, openPropertiesIconClassNames); } public override async run(context: ExecutionPlanView): Promise { + this.telemetryService + .createActionEvent(TelemetryKeys.TelemetryView.ExecutionPlan, TelemetryKeys.TelemetryAction.OpenExecutionPlanProperties) + .withAdditionalProperties({ source: this.source }) + .send(); + context.propertiesView.toggleVisibility(); } } @@ -299,11 +317,18 @@ export class ZoomInAction extends Action { public static ID = 'ep.ZoomInAction'; public static LABEL = localize('executionPlanZoomInActionLabel', "Zoom In"); - constructor() { + constructor(private source: ExecutionPlanActionSource, + @IAdsTelemetryService private readonly telemetryService: IAdsTelemetryService + ) { super(ZoomInAction.ID, ZoomInAction.LABEL, zoomInIconClassNames); } public override async run(context: ExecutionPlanView): Promise { + this.telemetryService + .createActionEvent(TelemetryKeys.TelemetryView.ExecutionPlan, TelemetryKeys.TelemetryAction.ZoomIn) + .withAdditionalProperties({ source: this.source }) + .send(); + context.executionPlanDiagram.zoomIn(); } } @@ -312,11 +337,18 @@ export class ZoomOutAction extends Action { public static ID = 'ep.ZoomOutAction'; public static LABEL = localize('executionPlanZoomOutActionLabel', "Zoom Out"); - constructor() { + constructor(private source: ExecutionPlanActionSource, + @IAdsTelemetryService private readonly telemetryService: IAdsTelemetryService + ) { super(ZoomOutAction.ID, ZoomOutAction.LABEL, zoomOutIconClassNames); } public override async run(context: ExecutionPlanView): Promise { + this.telemetryService + .createActionEvent(TelemetryKeys.TelemetryView.ExecutionPlan, TelemetryKeys.TelemetryAction.ZoomOut) + .withAdditionalProperties({ source: this.source }) + .send(); + context.executionPlanDiagram.zoomOut(); } } @@ -325,11 +357,18 @@ export class ZoomToFitAction extends Action { public static ID = 'ep.FitGraph'; public static LABEL = localize('executionPlanFitGraphLabel', "Zoom to fit"); - constructor() { + constructor(private source: ExecutionPlanActionSource, + @IAdsTelemetryService private readonly telemetryService: IAdsTelemetryService + ) { super(ZoomToFitAction.ID, ZoomToFitAction.LABEL, zoomToFitIconClassNames); } public override async run(context: ExecutionPlanView): Promise { + this.telemetryService + .createActionEvent(TelemetryKeys.TelemetryView.ExecutionPlan, TelemetryKeys.TelemetryAction.ZoomToFit) + .withAdditionalProperties({ source: this.source }) + .send(); + context.executionPlanDiagram.zoomToFit(); } } @@ -371,11 +410,18 @@ export class CustomZoomAction extends Action { public static ID = 'ep.customZoom'; public static LABEL = localize('executionPlanCustomZoom', "Custom Zoom"); - constructor() { + constructor(private source: ExecutionPlanActionSource, + @IAdsTelemetryService private readonly telemetryService: IAdsTelemetryService + ) { super(CustomZoomAction.ID, CustomZoomAction.LABEL, customZoomIconClassNames); } public override async run(context: ExecutionPlanView): Promise { + this.telemetryService + .createActionEvent(TelemetryKeys.TelemetryView.ExecutionPlan, TelemetryKeys.TelemetryAction.CustomZoom) + .withAdditionalProperties({ source: this.source }) + .send(); + context.widgetController.toggleWidget(context._instantiationService.createInstance(CustomZoomWidget, context.widgetController, context.executionPlanDiagram)); } } @@ -384,11 +430,18 @@ export class SearchNodeAction extends Action { public static ID = 'ep.searchNode'; public static LABEL = localize('executionPlanSearchNodeAction', "Find Node"); - constructor() { + constructor(private source: ExecutionPlanActionSource, + @IAdsTelemetryService private readonly telemetryService: IAdsTelemetryService + ) { super(SearchNodeAction.ID, SearchNodeAction.LABEL, searchIconClassNames); } public override async run(context: ExecutionPlanView): Promise { + this.telemetryService + .createActionEvent(TelemetryKeys.TelemetryView.ExecutionPlan, TelemetryKeys.TelemetryAction.FindNode) + .withAdditionalProperties({ source: this.source }) + .send(); + context.widgetController.toggleWidget(context._instantiationService.createInstance(NodeSearchWidget, context.widgetController, context.executionPlanDiagram)); } } diff --git a/src/sql/workbench/contrib/queryPlan/browser/topOperations.ts b/src/sql/workbench/contrib/queryPlan/browser/topOperations.ts index 7c4dace00a..8d42b82d94 100644 --- a/src/sql/workbench/contrib/queryPlan/browser/topOperations.ts +++ b/src/sql/workbench/contrib/queryPlan/browser/topOperations.ts @@ -15,6 +15,8 @@ import { attachTableStyler } from 'sql/platform/theme/common/styler'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TableDataView } from 'sql/base/browser/ui/table/tableDataView'; import { TopOperationsState } from 'sql/workbench/common/editor/query/topOperationsState'; +import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry'; +import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys'; const topOperationColumns: Array> = [ { name: localize('topOperations.operation', "Operation"), field: 'operation', sortable: true, width: 300 }, @@ -55,7 +57,10 @@ export class TopOperationsView extends Disposable implements IPanelView { private container = document.createElement('div'); private dataView = new TableDataView(); - constructor(@IThemeService private themeService: IThemeService) { + constructor( + @IThemeService private themeService: IThemeService, + @IAdsTelemetryService private readonly telemetryService: IAdsTelemetryService + ) { super(); this.table = new Table(this.container, { columns: topOperationColumns, @@ -71,6 +76,8 @@ export class TopOperationsView extends Disposable implements IPanelView { public render(container: HTMLElement): void { container.appendChild(this.container); + + this.telemetryService.sendActionEvent(TelemetryKeys.TelemetryView.ExecutionPlan, TelemetryKeys.TelemetryAction.ViewTopOperations); } public layout(dimension: Dimension): void {