mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Add telemetry for notebook toolbar actions (#19750)
* add telemetry for notebook toolbar actions * fix tests * remove events with no metadata + connection info * add optional connectioninfo param * fix param
This commit is contained in:
@@ -115,6 +115,9 @@ export const enum NbTelemetryAction {
|
|||||||
RunAll = 'RunNotebook',
|
RunAll = 'RunNotebook',
|
||||||
AddCell = 'AddCell',
|
AddCell = 'AddCell',
|
||||||
KernelChanged = 'KernelChanged',
|
KernelChanged = 'KernelChanged',
|
||||||
|
ConnectionChanged = 'ConnectionChanged',
|
||||||
|
TrustChanged = 'TrustChanged',
|
||||||
|
RunWithParameters = 'RunWithParameters',
|
||||||
NewNotebookFromConnections = 'NewNotebookWithConnectionProfile',
|
NewNotebookFromConnections = 'NewNotebookWithConnectionProfile',
|
||||||
UndoCell = 'UndoCell',
|
UndoCell = 'UndoCell',
|
||||||
RedoCell = 'RedoCell',
|
RedoCell = 'RedoCell',
|
||||||
|
|||||||
@@ -362,6 +362,9 @@ export class TrustedAction extends ToggleableAction {
|
|||||||
public override async run(context: URI): Promise<void> {
|
public override async run(context: URI): Promise<void> {
|
||||||
const editor = this._notebookService.findNotebookEditor(context);
|
const editor = this._notebookService.findNotebookEditor(context);
|
||||||
this.trusted = !this.trusted;
|
this.trusted = !this.trusted;
|
||||||
|
editor.model.sendNotebookTelemetryActionEvent(TelemetryKeys.NbTelemetryAction.TrustChanged, {
|
||||||
|
trust: this.trusted
|
||||||
|
});
|
||||||
editor.model.trustedMode = this.trusted;
|
editor.model.trustedMode = this.trusted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -472,6 +475,9 @@ export class RunParametersAction extends TooltipFromLabelAction {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
editor.model.sendNotebookTelemetryActionEvent(TelemetryKeys.NbTelemetryAction.RunWithParameters, {
|
||||||
|
kernel: editor.model.languageInfo.name
|
||||||
|
});
|
||||||
// Set defaultParameters to the parameter values in parameter cell
|
// Set defaultParameters to the parameter values in parameter cell
|
||||||
let defaultParameters = new Map<string, string>();
|
let defaultParameters = new Map<string, string>();
|
||||||
for (let cell of editor?.cells) {
|
for (let cell of editor?.cells) {
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ import { MockQuickInputService } from 'sql/workbench/contrib/notebook/test/commo
|
|||||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||||
import { Separator } from 'vs/base/common/actions';
|
import { Separator } from 'vs/base/common/actions';
|
||||||
import { INotebookView, INotebookViews } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
|
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';
|
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
|
||||||
|
|
||||||
class TestClientSession extends ClientSessionStub {
|
class TestClientSession extends ClientSessionStub {
|
||||||
@@ -111,9 +109,6 @@ class TestNotebookModel extends NotebookModelStub {
|
|||||||
public override getStandardKernelFromName(name: string): IStandardKernelWithProvider {
|
public override getStandardKernelFromName(name: string): IStandardKernelWithProvider {
|
||||||
return this._standardKernelsMap.get(name);
|
return this._standardKernelsMap.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override sendNotebookTelemetryActionEvent(action: TelemetryKeys.TelemetryAction | TelemetryKeys.NbTelemetryAction, additionalProperties?: ITelemetryEventProperties): void {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suite('Notebook Actions', function (): void {
|
suite('Notebook Actions', function (): void {
|
||||||
@@ -138,10 +133,11 @@ suite('Notebook Actions', function (): void {
|
|||||||
let testCellType: CellType = 'code';
|
let testCellType: CellType = 'code';
|
||||||
let actualCellType: CellType;
|
let actualCellType: CellType;
|
||||||
|
|
||||||
|
|
||||||
let action = new AddCellAction('TestId', 'TestLabel', 'TestClass', mockNotebookService.object);
|
let action = new AddCellAction('TestId', 'TestLabel', 'TestClass', mockNotebookService.object);
|
||||||
action.cellType = testCellType;
|
action.cellType = testCellType;
|
||||||
|
|
||||||
|
mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel);
|
||||||
|
|
||||||
// Normal use case
|
// Normal use case
|
||||||
mockNotebookEditor.setup(x => x.addCell(TypeMoq.It.isAny(), TypeMoq.It.isAnyNumber())).returns((cellType, index) => { actualCellType = cellType; });
|
mockNotebookEditor.setup(x => x.addCell(TypeMoq.It.isAny(), TypeMoq.It.isAnyNumber())).returns((cellType, index) => { actualCellType = cellType; });
|
||||||
let mockNotebookComponent = TypeMoq.Mock.ofType<INotebookEditor>(NotebookComponentStub);
|
let mockNotebookComponent = TypeMoq.Mock.ofType<INotebookEditor>(NotebookComponentStub);
|
||||||
@@ -154,6 +150,7 @@ suite('Notebook Actions', function (): void {
|
|||||||
|
|
||||||
// Handle error case
|
// Handle error case
|
||||||
mockNotebookEditor.reset();
|
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'));
|
mockNotebookEditor.setup(x => x.addCell(TypeMoq.It.isAny(), TypeMoq.It.isAnyNumber())).throws(new Error('Test Error'));
|
||||||
await assert.rejects(action.run(URI.parse('untitled')));
|
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<void> {
|
test('Clear All Outputs Action', async function (): Promise<void> {
|
||||||
let action = new ClearAllOutputsAction('TestId', true, mockNotebookService.object);
|
let action = new ClearAllOutputsAction('TestId', true, mockNotebookService.object);
|
||||||
|
|
||||||
|
mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel);
|
||||||
|
|
||||||
// Normal use case
|
// Normal use case
|
||||||
mockNotebookEditor.setup(c => c.clearAllOutputs()).returns(() => Promise.resolve(true));
|
mockNotebookEditor.setup(c => c.clearAllOutputs()).returns(() => Promise.resolve(true));
|
||||||
|
|
||||||
@@ -169,6 +168,7 @@ suite('Notebook Actions', function (): void {
|
|||||||
|
|
||||||
// Handle failure case
|
// Handle failure case
|
||||||
mockNotebookEditor.reset();
|
mockNotebookEditor.reset();
|
||||||
|
mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel);
|
||||||
mockNotebookEditor.setup(c => c.clearAllOutputs()).returns(() => Promise.resolve(false));
|
mockNotebookEditor.setup(c => c.clearAllOutputs()).returns(() => Promise.resolve(false));
|
||||||
|
|
||||||
await action.run(testUri);
|
await action.run(testUri);
|
||||||
@@ -182,11 +182,9 @@ suite('Notebook Actions', function (): void {
|
|||||||
let action = new TrustedAction('TestId', true, mockNotebookService.object);
|
let action = new TrustedAction('TestId', true, mockNotebookService.object);
|
||||||
assert.strictEqual(action.trusted, false, 'Should not be trusted by default');
|
assert.strictEqual(action.trusted, false, 'Should not be trusted by default');
|
||||||
|
|
||||||
const testNotebookModel: INotebookModel = <INotebookModel>{
|
testNotebookModel.trustedMode = false;
|
||||||
trustedMode: false
|
|
||||||
};
|
|
||||||
|
|
||||||
mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel);
|
mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel);
|
||||||
|
|
||||||
// Normal use case
|
// Normal use case
|
||||||
await action.run(testUri);
|
await action.run(testUri);
|
||||||
assert.strictEqual(action.trusted, true, 'Should be trusted after toggling trusted state');
|
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<void> {
|
test('Run All Cells Action', async function (): Promise<void> {
|
||||||
const testNotebookModel = TypeMoq.Mock.ofType<INotebookModel>(NotebookModelStub);
|
|
||||||
testNotebookModel.setup(x => x.getMetaValue(TypeMoq.It.isAny())).returns(() => undefined);
|
|
||||||
mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel.object);
|
|
||||||
|
|
||||||
let mockNotification = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService);
|
let mockNotification = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService);
|
||||||
mockNotification.setup(n => n.notify(TypeMoq.It.isAny()));
|
mockNotification.setup(n => n.notify(TypeMoq.It.isAny()));
|
||||||
|
|
||||||
let action = new RunAllCellsAction('TestId', 'TestLabel', 'TestClass', mockNotification.object, mockNotebookService.object);
|
let action = new RunAllCellsAction('TestId', 'TestLabel', 'TestClass', mockNotification.object, mockNotebookService.object);
|
||||||
|
|
||||||
|
mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel);
|
||||||
|
|
||||||
// Normal use case
|
// Normal use case
|
||||||
mockNotebookEditor.setup(c => c.runAllCells()).returns(() => Promise.resolve(true));
|
mockNotebookEditor.setup(c => c.runAllCells()).returns(() => Promise.resolve(true));
|
||||||
|
|
||||||
@@ -216,6 +213,7 @@ suite('Notebook Actions', function (): void {
|
|||||||
|
|
||||||
// Handle errors
|
// Handle errors
|
||||||
mockNotebookEditor.reset();
|
mockNotebookEditor.reset();
|
||||||
|
mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel);
|
||||||
mockNotebookEditor.setup(c => c.runAllCells()).throws(new Error('Test Error'));
|
mockNotebookEditor.setup(c => c.runAllCells()).throws(new Error('Test Error'));
|
||||||
|
|
||||||
await action.run(testUri);
|
await action.run(testUri);
|
||||||
@@ -233,6 +231,7 @@ suite('Notebook Actions', function (): void {
|
|||||||
isCollapsed: false
|
isCollapsed: false
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
mockNotebookEditor.setup(x => x.model).returns(() => testNotebookModel);
|
||||||
mockNotebookEditor.setup(x => x.cells).returns(() => testCells);
|
mockNotebookEditor.setup(x => x.cells).returns(() => testCells);
|
||||||
|
|
||||||
// Collapse cells case
|
// Collapse cells case
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import { uriPrefixes } from 'sql/platform/connection/common/utils';
|
|||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { getErrorMessage } from 'vs/base/common/errors';
|
import { getErrorMessage } from 'vs/base/common/errors';
|
||||||
import { notebookConstants } from 'sql/workbench/services/notebook/browser/interfaces';
|
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 { Deferred } from 'sql/base/common/promise';
|
||||||
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
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);
|
let properties: ITelemetryEventProperties = deepClone(additionalProperties);
|
||||||
properties['azdata_notebook_guid'] = this.getMetaValue('azdata_notebook_guid');
|
properties['azdata_notebook_guid'] = this.getMetaValue('azdata_notebook_guid');
|
||||||
this.adstelemetryService.createActionEvent(TelemetryKeys.TelemetryView.Notebook, action)
|
let event: ITelemetryEvent = this.adstelemetryService.createActionEvent(TelemetryKeys.TelemetryView.Notebook, action)
|
||||||
.withAdditionalProperties(properties)
|
.withAdditionalProperties(properties);
|
||||||
.send();
|
if (connectionInfo) {
|
||||||
|
event.withConnectionInfo(connectionInfo);
|
||||||
|
}
|
||||||
|
event.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadContentMetadata(metadata: INotebookMetadataInternal): void {
|
private loadContentMetadata(metadata: INotebookMetadataInternal): void {
|
||||||
@@ -1317,6 +1320,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
this._onValidConnectionSelected.fire(false);
|
this._onValidConnectionSelected.fire(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.sendNotebookTelemetryActionEvent(TelemetryKeys.NbTelemetryAction.ConnectionChanged, undefined, newConnection.toIConnectionProfile());
|
||||||
} else {
|
} else {
|
||||||
this._onValidConnectionSelected.fire(false);
|
this._onValidConnectionSelected.fire(false);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user