Skip to content

Commit 68d7acb

Browse files
authored
Send telemetry when gather survey link is clicked. (microsoft#10683)
* Sending gather quality report (works - not pretty) * Actually open the gather survey And whitelist the command that does so. We don't necessarily want to open the door of being able to execute arbitrary commands to notebooks. Yet. * Fixup for PR submit * Tweak to work correctly with surveymonkey
1 parent 790cd6d commit 68d7acb

8 files changed

Lines changed: 35 additions & 6 deletions

File tree

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,11 @@
596596
"title": "%DataScience.selectKernel%",
597597
"category": "Python",
598598
"enablement": "python.datascience.isnativeactive"
599+
},
600+
{
601+
"command": "python.datascience.gatherquality",
602+
"title": "%DataScience.gatherGood%",
603+
"category": "Python"
599604
}
600605
],
601606
"menus": {

package.nls.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@
418418
"DataScience.findJupyterCommandProgressCheckInterpreter": "Checking {0}.",
419419
"DataScience.findJupyterCommandProgressSearchCurrentPath": "Searching current path.",
420420
"DataScience.gatheredScriptDescription":"# This file was generated by an experimental feature called 'Gather'.\n#\n# The intent is that it contains only the code required to produce\n# the same results as the cell originally selected for gathering.\n# Please note that the Python analysis is quite conservative, so if\n# it is unsure whether a line of code is necessary for execution, it\n# will err on the side of including it.\n#\n# Please let us know if you are satisfied with what was gathered here:\n# https://aka.ms/gathersurvey\n\n",
421-
"DataScience.gatheredNotebookDescriptionInMarkdown": "## Gathered Notebook\nGathered from ```{0}```\n\n| | |\n|---|---|\n|  &nbsp|This notebook was generated by an experimental feature called \"Gather\". The intent is that it contains only the code and cells required to produce the same results as the cell originally selected for gathering. Please note that the Python analysis is quite conservative, so if it is unsure whether a line of code is necessary for execution, it will err on the side of including it.|\n\n**Are you satisfied with the code that was gathered?**\n\n[Yes](https://aka.ms/gathersurvey?succeed_value=1) [No](https://aka.ms/gathersurvey?succeed_value=0)",
421+
"DataScience.gatheredNotebookDescriptionInMarkdown": "## Gathered Notebook\nGathered from ```{0}```\n\n| | |\n|---|---|\n|  &nbsp|This notebook was generated by an experimental feature called \"Gather\". The intent is that it contains only the code and cells required to produce the same results as the cell originally selected for gathering. Please note that the Python analysis is quite conservative, so if it is unsure whether a line of code is necessary for execution, it will err on the side of including it.|\n\n**Are you satisfied with the code that was gathered?**\n\n[Yes](https://command:python.datascience.gatherquality?yes) [No](https://command:python.datascience.gatherquality?no)",
422422
"DataScience.savePngTitle": "Save Image",
423423
"DataScience.jupyterSelectURIQuickPickTitle": "Pick how to connect to Jupyter",
424424
"DataScience.jupyterSelectURIQuickPickPlaceholder": "Choose an option",

src/client/common/application/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,5 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu
161161
[DSCommands.SaveNotebookNonCustomEditor]: [Uri];
162162
[DSCommands.SaveAsNotebookNonCustomEditor]: [Uri, Uri];
163163
[DSCommands.OpenNotebookNonCustomEditor]: [Uri];
164+
[DSCommands.GatherQuality]: [string];
164165
}

src/client/common/utils/localize.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ export namespace DataScience {
726726
);
727727
export const gatheredNotebookDescriptionInMarkdown = localize(
728728
'DataScience.gatheredNotebookDescriptionInMarkdown',
729-
'# Gathered Notebook\nGathered from ```{0}```\n\n| | |\n|---|---|\n|  &nbsp|This notebook was generated by an experimental feature called "Gather". The intent is that it contains only the code and cells required to produce the same results as the cell originally selected for gathering. Please note that the Python analysis is quite conservative, so if it is unsure whether a line of code is necessary for execution, it will err on the side of including it.|\n\n**Are you satisfied with the code that was gathered?**\n\n[Yes](https://aka.ms/gathersurvey?succeed_value=1) [No](https://aka.ms/gathersurvey?succeed_value=0)'
729+
'# Gathered Notebook\nGathered from ```{0}```\n\n| | |\n|---|---|\n|  &nbsp|This notebook was generated by an experimental feature called "Gather". The intent is that it contains only the code and cells required to produce the same results as the cell originally selected for gathering. Please note that the Python analysis is quite conservative, so if it is unsure whether a line of code is necessary for execution, it will err on the side of including it.|\n\n**Are you satisfied with the code that was gathered?**\n\n[Yes](https://command:python.datascience.gatherquality?yes) [No](https://command:python.datascience.gatherquality?no)'
730730
);
731731
export const savePngTitle = localize('DataScience.savePngTitle', 'Save Image');
732732
export const fallbackToUseActiveInterpeterAsKernel = localize(

src/client/datascience/commands/commandRegistry.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
'use strict';
55

66
import { inject, injectable, multiInject, named, optional } from 'inversify';
7-
import { CodeLens, Range } from 'vscode';
7+
import { CodeLens, env, Range, Uri } from 'vscode';
88
import { ICommandNameArgumentTypeMapping } from '../../common/application/commands';
99
import { ICommandManager, IDebugService, IDocumentManager } from '../../common/application/types';
1010
import { IDisposable, IOutputChannel } from '../../common/types';
1111
import { DataScience } from '../../common/utils/localize';
12-
import { captureTelemetry } from '../../telemetry';
12+
import { captureTelemetry, sendTelemetryEvent } from '../../telemetry';
1313
import { Commands, JUPYTER_OUTPUT_CHANNEL, Telemetry } from '../constants';
1414
import {
1515
ICodeWatcher,
@@ -68,6 +68,7 @@ export class CommandRegistry implements IDisposable {
6868
this.registerCommand(Commands.DebugCurrentCellPalette, this.debugCurrentCellFromCursor);
6969
this.registerCommand(Commands.CreateNewNotebook, this.createNewNotebook);
7070
this.registerCommand(Commands.ViewJupyterOutput, this.viewJupyterOutput);
71+
this.registerCommand(Commands.GatherQuality, this.reportGatherQuality);
7172
if (this.commandListeners) {
7273
this.commandListeners.forEach((listener: IDataScienceCommandListener) => {
7374
listener.register(this.commandManager);
@@ -344,4 +345,9 @@ export class CommandRegistry implements IDisposable {
344345
// Ask our code lens provider to find the matching code watcher for the current document
345346
return this.dataScienceCodeLensProvider.getCodeWatcher(activeEditor.document);
346347
}
348+
349+
private reportGatherQuality(val: string) {
350+
sendTelemetryEvent(Telemetry.GatherQualityReport, undefined, { result: val === 'no' ? 'no' : 'yes' });
351+
env.openExternal(Uri.parse(`https://aka.ms/gathersurvey?succeed=${val}`));
352+
}
347353
}

src/client/datascience/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export namespace Commands {
8181
export const SaveNotebookNonCustomEditor = 'python.datascience.notebookeditor.save';
8282
export const SaveAsNotebookNonCustomEditor = 'python.datascience.notebookeditor.saveAs';
8383
export const OpenNotebookNonCustomEditor = 'python.datascience.notebookeditor.open';
84+
export const GatherQuality = 'python.datascience.gatherquality';
8485
}
8586

8687
export namespace CodeLensCommands {
@@ -285,6 +286,7 @@ export enum Telemetry {
285286
KernelInvalid = 'DS_INTERNAL.INVALID_KERNEL_USED',
286287
GatherCompleted = 'DATASCIENCE.GATHER_COMPLETED',
287288
GatheredNotebookSaved = 'DATASCIENCE.GATHERED_NOTEBOOK_SAVED',
289+
GatherQualityReport = 'DS_INTERNAL.GATHER_QUALITY_REPORT',
288290
ZMQNotSupported = 'DATASCIENCE.ZMQ_NATIVE_BINARIES_NOT_LOADING'
289291
}
290292

src/client/datascience/interactive-common/linkProvider.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import '../../common/extensions';
55

66
import { inject, injectable } from 'inversify';
7-
import { Event, EventEmitter, Position, Range, Selection, TextEditorRevealType, Uri } from 'vscode';
7+
import { commands, Event, EventEmitter, Position, Range, Selection, TextEditorRevealType, Uri } from 'vscode';
88

99
import { IApplicationShell, ICommandManager, IDocumentManager } from '../../common/application/types';
1010
import { IFileSystem } from '../../common/platform/types';
@@ -15,6 +15,10 @@ import { InteractiveWindowMessages } from './interactiveWindowTypes';
1515

1616
const LineQueryRegex = /line=(\d+)/;
1717

18+
// The following list of commands represent those that can be executed
19+
// in a markdown cell using the syntax: https://command:[my.vscode.command].
20+
const linkCommandWhitelist = ['python.datascience.gatherquality'];
21+
1822
// tslint:disable: no-any
1923
@injectable()
2024
export class LinkProvider implements IInteractiveWindowListener {
@@ -40,9 +44,16 @@ export class LinkProvider implements IInteractiveWindowListener {
4044
case InteractiveWindowMessages.OpenLink:
4145
if (payload) {
4246
// Special case file URIs
43-
const href = payload.toString();
47+
const href: string = payload.toString();
4448
if (href.startsWith('file')) {
4549
this.openFile(href);
50+
} else if (href.startsWith('https://command:')) {
51+
const temp: string = href.split(':')[2];
52+
const command = temp.split('/?')[0];
53+
const params: string[] = temp.split('/?')[1].split(',');
54+
if (linkCommandWhitelist.includes(command)) {
55+
commands.executeCommand(command, params);
56+
}
4657
} else {
4758
this.applicationShell.openUrl(href);
4859
}

src/client/telemetry/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,10 @@ export interface IEventNamePropertyMapping {
19001900
* Telemetry event sent when a gathered notebook has been saved by the user.
19011901
*/
19021902
[Telemetry.GatheredNotebookSaved]: undefined | never;
1903+
/**
1904+
* Telemetry event sent when the user reports whether Gathered notebook was good or not
1905+
*/
1906+
[Telemetry.GatherQualityReport]: { result: 'yes' | 'no' };
19031907
/**
19041908
* Telemetry event sent when the ZMQ native binaries do not work.
19051909
*/

0 commit comments

Comments
 (0)