diff --git a/src/sql/platform/telemetry/common/telemetryKeys.ts b/src/sql/platform/telemetry/common/telemetryKeys.ts index 404afa50f6..f4849e8929 100644 --- a/src/sql/platform/telemetry/common/telemetryKeys.ts +++ b/src/sql/platform/telemetry/common/telemetryKeys.ts @@ -115,6 +115,9 @@ export const enum NbTelemetryAction { RunAll = 'RunNotebook', AddCell = 'AddCell', KernelChanged = 'KernelChanged', + ConnectionChanged = 'ConnectionChanged', + TrustChanged = 'TrustChanged', + RunWithParameters = 'RunWithParameters', NewNotebookFromConnections = 'NewNotebookWithConnectionProfile', UndoCell = 'UndoCell', RedoCell = 'RedoCell', diff --git a/src/sql/workbench/contrib/notebook/browser/notebookActions.ts b/src/sql/workbench/contrib/notebook/browser/notebookActions.ts index dbfc43df4e..350062d79b 100644 --- a/src/sql/workbench/contrib/notebook/browser/notebookActions.ts +++ b/src/sql/workbench/contrib/notebook/browser/notebookActions.ts @@ -362,6 +362,9 @@ export class TrustedAction extends ToggleableAction { public override async run(context: URI): Promise { const editor = this._notebookService.findNotebookEditor(context); this.trusted = !this.trusted; + editor.model.sendNotebookTelemetryActionEvent(TelemetryKeys.NbTelemetryAction.TrustChanged, { + trust: this.trusted + }); editor.model.trustedMode = this.trusted; } } @@ -472,6 +475,9 @@ export class RunParametersAction extends TooltipFromLabelAction { }); return; } + editor.model.sendNotebookTelemetryActionEvent(TelemetryKeys.NbTelemetryAction.RunWithParameters, { + kernel: editor.model.languageInfo.name + }); // Set defaultParameters to the parameter values in parameter cell let defaultParameters = new Map(); for (let cell of editor?.cells) { diff --git a/src/sql/workbench/contrib/notebook/test/browser/notebookActions.test.ts b/src/sql/workbench/contrib/notebook/test/browser/notebookActions.test.ts index 82726a8b34..e41e23eb6a 100644 --- a/src/sql/workbench/contrib/notebook/test/browser/notebookActions.test.ts +++ b/src/sql/workbench/contrib/notebook/test/browser/notebookActions.test.ts @@ -29,8 +29,6 @@ import { MockQuickInputService } from 'sql/workbench/contrib/notebook/test/commo import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { Separator } from 'vs/base/common/actions'; import { INotebookView, INotebookViews } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews'; -import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys'; -import { ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry'; import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants'; class TestClientSession extends ClientSessionStub { @@ -111,9 +109,6 @@ class TestNotebookModel extends NotebookModelStub { public override getStandardKernelFromName(name: string): IStandardKernelWithProvider { return this._standardKernelsMap.get(name); } - - public override sendNotebookTelemetryActionEvent(action: TelemetryKeys.TelemetryAction | TelemetryKeys.NbTelemetryAction, additionalProperties?: ITelemetryEventProperties): void { - } } suite('Notebook Actions', function (): void { @@ -138,10 +133,11 @@ suite('Notebook Actions', function (): void { let testCellType: CellType = 'code'; let actualCellType: CellType; - let action = new AddCellAction('TestId', 'TestLabel', 'TestClass', mockNotebookService.object); action.cellType = testCellType; + mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel); + // Normal use case mockNotebookEditor.setup(x => x.addCell(TypeMoq.It.isAny(), TypeMoq.It.isAnyNumber())).returns((cellType, index) => { actualCellType = cellType; }); let mockNotebookComponent = TypeMoq.Mock.ofType(NotebookComponentStub); @@ -154,6 +150,7 @@ suite('Notebook Actions', function (): void { // Handle error case mockNotebookEditor.reset(); + mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel); mockNotebookEditor.setup(x => x.addCell(TypeMoq.It.isAny(), TypeMoq.It.isAnyNumber())).throws(new Error('Test Error')); await assert.rejects(action.run(URI.parse('untitled'))); }); @@ -161,6 +158,8 @@ suite('Notebook Actions', function (): void { test('Clear All Outputs Action', async function (): Promise { let action = new ClearAllOutputsAction('TestId', true, mockNotebookService.object); + mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel); + // Normal use case mockNotebookEditor.setup(c => c.clearAllOutputs()).returns(() => Promise.resolve(true)); @@ -169,6 +168,7 @@ suite('Notebook Actions', function (): void { // Handle failure case mockNotebookEditor.reset(); + mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel); mockNotebookEditor.setup(c => c.clearAllOutputs()).returns(() => Promise.resolve(false)); await action.run(testUri); @@ -182,11 +182,9 @@ suite('Notebook Actions', function (): void { let action = new TrustedAction('TestId', true, mockNotebookService.object); assert.strictEqual(action.trusted, false, 'Should not be trusted by default'); - const testNotebookModel: INotebookModel = { - trustedMode: false - }; - + testNotebookModel.trustedMode = false; mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel); + // Normal use case await action.run(testUri); assert.strictEqual(action.trusted, true, 'Should be trusted after toggling trusted state'); @@ -199,15 +197,14 @@ suite('Notebook Actions', function (): void { }); test('Run All Cells Action', async function (): Promise { - const testNotebookModel = TypeMoq.Mock.ofType(NotebookModelStub); - testNotebookModel.setup(x => x.getMetaValue(TypeMoq.It.isAny())).returns(() => undefined); - mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel.object); let mockNotification = TypeMoq.Mock.ofType(TestNotificationService); mockNotification.setup(n => n.notify(TypeMoq.It.isAny())); let action = new RunAllCellsAction('TestId', 'TestLabel', 'TestClass', mockNotification.object, mockNotebookService.object); + mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel); + // Normal use case mockNotebookEditor.setup(c => c.runAllCells()).returns(() => Promise.resolve(true)); @@ -216,6 +213,7 @@ suite('Notebook Actions', function (): void { // Handle errors mockNotebookEditor.reset(); + mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel); mockNotebookEditor.setup(c => c.runAllCells()).throws(new Error('Test Error')); await action.run(testUri); @@ -233,6 +231,7 @@ suite('Notebook Actions', function (): void { isCollapsed: false }]; + mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel); mockNotebookEditor.setup(x => x.cells).returns(() => testCells); // Collapse cells case diff --git a/src/sql/workbench/services/notebook/browser/models/notebookModel.ts b/src/sql/workbench/services/notebook/browser/models/notebookModel.ts index b176470587..e10a84847a 100644 --- a/src/sql/workbench/services/notebook/browser/models/notebookModel.ts +++ b/src/sql/workbench/services/notebook/browser/models/notebookModel.ts @@ -25,7 +25,7 @@ import { uriPrefixes } from 'sql/platform/connection/common/utils'; import { ILogService } from 'vs/platform/log/common/log'; import { getErrorMessage } from 'vs/base/common/errors'; import { notebookConstants } from 'sql/workbench/services/notebook/browser/interfaces'; -import { IAdsTelemetryService, ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry'; +import { IAdsTelemetryService, ITelemetryEvent, ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry'; import { Deferred } from 'sql/base/common/promise'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; @@ -478,12 +478,15 @@ export class NotebookModel extends Disposable implements INotebookModel { } } - public sendNotebookTelemetryActionEvent(action: TelemetryKeys.TelemetryAction | TelemetryKeys.NbTelemetryAction, additionalProperties: ITelemetryEventProperties = {}): void { + public sendNotebookTelemetryActionEvent(action: TelemetryKeys.TelemetryAction | TelemetryKeys.NbTelemetryAction, additionalProperties: ITelemetryEventProperties = {}, connectionInfo?: IConnectionProfile): void { let properties: ITelemetryEventProperties = deepClone(additionalProperties); properties['azdata_notebook_guid'] = this.getMetaValue('azdata_notebook_guid'); - this.adstelemetryService.createActionEvent(TelemetryKeys.TelemetryView.Notebook, action) - .withAdditionalProperties(properties) - .send(); + let event: ITelemetryEvent = this.adstelemetryService.createActionEvent(TelemetryKeys.TelemetryView.Notebook, action) + .withAdditionalProperties(properties); + if (connectionInfo) { + event.withConnectionInfo(connectionInfo); + } + event.send(); } private loadContentMetadata(metadata: INotebookMetadataInternal): void { @@ -1317,6 +1320,7 @@ export class NotebookModel extends Disposable implements INotebookModel { this._onValidConnectionSelected.fire(false); } }); + this.sendNotebookTelemetryActionEvent(TelemetryKeys.NbTelemetryAction.ConnectionChanged, undefined, newConnection.toIConnectionProfile()); } else { this._onValidConnectionSelected.fire(false); }