Skip to content

Commit 5469799

Browse files
VSCODE-224: Telemetry document edited from playground (#235)
* feat: add telemetry events for documents edited from a playground (VSCODE-224) * refactor: puch instance info type * refactor: clean up some names and types * chore: update type dependencies * chore: rollback to @types/vscode@^1.49.0 * refactor: promisify data service in telemetry
1 parent 7feb9f0 commit 5469799

29 files changed

+799
-453
lines changed

package-lock.json

Lines changed: 140 additions & 89 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -867,25 +867,24 @@
867867
"ws": "^7.2.3"
868868
},
869869
"devDependencies": {
870-
"@types/chai": "^4.2.9",
870+
"@types/analytics-node": "^3.1.4",
871+
"@types/chai": "^4.2.14",
871872
"@types/chai-fs": "^2.0.2",
872-
"@types/chai-json-schema": "^1.4.5",
873-
"@types/classnames": "^2.2.10",
873+
"@types/chai-json-schema": "^1.4.6",
874+
"@types/classnames": "^2.2.11",
874875
"@types/debug": "^4.1.5",
875-
"@types/enzyme": "^3.10.7",
876-
"@types/glob": "^7.1.1",
877-
"@types/jest": "^26.0.14",
878-
"@types/keytar": "4.4.2",
879-
"@types/mocha": "^8.0.3",
880-
"@types/node": "^14.11.5",
881-
"@types/react": "^16.9.25",
882-
"@types/react-dom": "^16.9.5",
883-
"@types/redux": "^3.6.0",
884-
"@types/sinon": "^9.0.1",
876+
"@types/enzyme": "^3.10.8",
877+
"@types/glob": "^7.1.3",
878+
"@types/jest": "^26.0.20",
879+
"@types/mocha": "^8.2.0",
880+
"@types/node": "^14.14.20",
881+
"@types/react": "^17.0.0",
882+
"@types/react-dom": "^17.0.0",
883+
"@types/sinon": "^9.0.10",
885884
"@types/vscode": "^1.49.0",
886-
"@types/ws": "^7.2.4",
887-
"@typescript-eslint/eslint-plugin": "^4.12.0",
888-
"@typescript-eslint/parser": "^4.12.0",
885+
"@types/ws": "^7.4.0",
886+
"@typescript-eslint/eslint-plugin": "^4.13.0",
887+
"@typescript-eslint/parser": "^4.13.0",
889888
"autoprefixer": "^9.7.5",
890889
"chai": "^4.2.0",
891890
"chai-as-promised": "^7.1.1",
@@ -909,24 +908,24 @@
909908
"meow": "^6.0.1",
910909
"mkdirp": "^1.0.4",
911910
"mocha": "^8.2.1",
912-
"mocha-junit-reporter": "^1.23.3",
911+
"mocha-junit-reporter": "^2.0.0",
913912
"mocha-multi": "^1.1.3",
914-
"mongodb-ace-autocompleter": "^0.4.13",
913+
"mongodb-ace-autocompleter": "^0.4.14",
915914
"mongodb-runner": "^4.8.0",
916915
"node-loader": "^0.6.0",
917916
"npm-run-all": "^4.1.5",
918917
"ora": "^4.0.3",
919918
"postcss-loader": "^3.0.0",
920919
"pre-commit": "^1.2.2",
921-
"sinon": "^9.0.0",
920+
"sinon": "^9.2.3",
922921
"sinon-chai": "^3.5.0",
923922
"style-loader": "^1.1.3",
924-
"ts-jest": "^26.4.1",
925-
"ts-loader": "^6.2.2",
926-
"ts-node": "^8.6.2",
923+
"ts-jest": "^26.4.4",
924+
"ts-loader": "^8.0.14",
925+
"ts-node": "^9.1.1",
927926
"typescript": "^4.1.3",
928-
"vsce": "^1.81.1",
929-
"vscode-test": "^1.3.0",
927+
"vsce": "^1.83.0",
928+
"vscode-test": "^1.4.1",
930929
"webpack": "^4.42.0",
931930
"webpack-cli": "^3.3.11",
932931
"xvfb-maybe": "^0.2.1"

src/connectionController.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { StatusView } from './views';
1010
import { EventEmitter } from 'events';
1111
import { StorageController, StorageVariables } from './storage';
1212
import { SavedConnection, StorageScope } from './storage/storageController';
13-
import TelemetryController from './telemetry/telemetryController';
13+
import TelemetryService from './telemetry/telemetryService';
1414
import { ext } from './extensionConstants';
1515
import { CONNECTION_STATUS } from './views/webview-app/extension-app-message-constants';
1616
import SSH_TUNNEL_TYPES from './views/webview-app/connection-model/constants/ssh-tunnel-types';
@@ -72,19 +72,19 @@ export default class ConnectionController {
7272

7373
private _statusView: StatusView;
7474
private _storageController: StorageController;
75-
private _telemetryController: TelemetryController;
75+
private _telemetryService: TelemetryService;
7676

7777
// Used by other parts of the extension that respond to changes in the connections.
7878
private eventEmitter: EventEmitter = new EventEmitter();
7979

8080
constructor(
8181
_statusView: StatusView,
8282
storageController: StorageController,
83-
telemetryController: TelemetryController
83+
telemetryService: TelemetryService
8484
) {
8585
this._statusView = _statusView;
8686
this._storageController = storageController;
87-
this._telemetryController = telemetryController;
87+
this._telemetryService = telemetryService;
8888
}
8989

9090
_loadSavedConnection = async (
@@ -250,8 +250,7 @@ export default class ConnectionController {
250250
newDataService: DataServiceType,
251251
connectionType: ConnectionTypes
252252
): void {
253-
// Send metrics to Segment
254-
this._telemetryController.trackNewConnection(
253+
this._telemetryService.trackNewConnection(
255254
newDataService,
256255
connectionType
257256
);

src/editors/editDocumentCodeLensProvider.ts

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as vscode from 'vscode';
22
import EXTENSION_COMMANDS from '../commands';
33
import type { OutputItem, ResultCodeLensInfo } from '../utils/types';
44
import ConnectionController from '../connectionController';
5+
import { DocumentSource } from '../telemetry/telemetryService';
56

67
export default class EditDocumentCodeLensProvider
78
implements vscode.CodeLensProvider {
@@ -22,20 +23,38 @@ implements vscode.CodeLensProvider {
2223
});
2324
}
2425

25-
updateCodeLensesPosition(playgroundResult: OutputItem): void {
26+
updateCodeLensesForPlayground(playgroundResult: OutputItem) {
27+
const source = DocumentSource.DOCUMENT_SOURCE_PLAYGROUND;
28+
2629
if (!playgroundResult || !playgroundResult.content) {
2730
this._codeLensesInfo = [];
2831

2932
return;
3033
}
3134

3235
const { content, namespace, type } = playgroundResult;
33-
const connectionId = this._connectionController.getActiveConnectionId();
34-
const codeLensesInfo: ResultCodeLensInfo[] = [];
36+
const data = { content, namespace, source };
3537

3638
// Show code lenses only for the list of documents or a single document
3739
// that are returned by the find() method.
38-
if (type === 'Cursor' && Array.isArray(content)) {
40+
if (type === 'Cursor') {
41+
this._updateCodeLensesForCursor(data);
42+
} else if (type === 'Document') {
43+
this._updateCodeLensesForDocument(data);
44+
}
45+
}
46+
47+
_updateCodeLensesForCursor(data: {
48+
content: any,
49+
namespace: string | null,
50+
source: string
51+
}) {
52+
const codeLensesInfo: ResultCodeLensInfo[] = [];
53+
54+
if (Array.isArray(data.content)) {
55+
const connectionId = this._connectionController.getActiveConnectionId();
56+
const { content, namespace, source } = data;
57+
3958
// When the playground result is the collection,
4059
// show the first code lense after [{.
4160
let line = 2;
@@ -45,23 +64,42 @@ implements vscode.CodeLensProvider {
4564
// to be able to save the editable document.
4665
if (item !== null && item._id && namespace) {
4766
codeLensesInfo.push({
48-
line,
4967
documentId: item._id,
68+
source,
69+
line,
5070
namespace,
5171
connectionId
5272
});
73+
5374
// To calculate the position of the next open curly bracket,
5475
// we stringify the object and use a regular expression
5576
// so we can count the number of lines.
5677
line += JSON.stringify(item, null, 2).split(/\r\n|\r|\n/).length;
5778
}
5879
});
59-
} else if (type === 'Document' && content._id && namespace) {
80+
}
81+
82+
this._codeLensesInfo = codeLensesInfo;
83+
this._onDidChangeCodeLenses.fire();
84+
}
85+
86+
_updateCodeLensesForDocument(data: {
87+
content: any,
88+
namespace: string | null,
89+
source: string
90+
}): void {
91+
const codeLensesInfo: ResultCodeLensInfo[] = [];
92+
const { content, namespace, source } = data;
93+
94+
if (content._id && namespace) {
95+
const connectionId = this._connectionController.getActiveConnectionId();
96+
6097
// When the playground result is the single document,
6198
// show the single code lense after {.
6299
codeLensesInfo.push({
63-
line: 1,
64100
documentId: content._id,
101+
source,
102+
line: 1,
65103
namespace,
66104
connectionId
67105
});

src/editors/editorsController.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ import PlaygroundController from './playgroundController';
1717
import DocumentIdStore from './documentIdStore';
1818
import MongoDBDocumentService, {
1919
DOCUMENT_ID_URI_IDENTIFIER,
20+
DOCUMENT_SOURCE_URI_IDENTIFIER,
2021
VIEW_DOCUMENT_SCHEME
2122
} from './mongoDBDocumentService';
2223
import { MemoryFileSystemProvider } from './memoryFileSystemProvider';
23-
import TelemetryController from '../telemetry/telemetryController';
24+
import TelemetryService from '../telemetry/telemetryService';
2425
import PlaygroundResultProvider, {
2526
PLAYGROUND_RESULT_SCHEME
2627
} from './playgroundResultProvider';
@@ -42,7 +43,7 @@ export default class EditorsController {
4243
_memoryFileSystemProvider: MemoryFileSystemProvider;
4344
_documentIdStore: DocumentIdStore;
4445
_mongoDBDocumentService: MongoDBDocumentService;
45-
_telemetryController: TelemetryController;
46+
_telemetryService: TelemetryService;
4647
_playgroundResultViewProvider: PlaygroundResultProvider;
4748
_activeConnectionCodeLensProvider: ActiveConnectionCodeLensProvider;
4849
_partialExecutionCodeLensProvider: PartialExecutionCodeLensProvider;
@@ -52,7 +53,7 @@ export default class EditorsController {
5253
connectionController: ConnectionController,
5354
playgroundController: PlaygroundController,
5455
statusView: StatusView,
55-
telemetryController: TelemetryController,
56+
telemetryService: TelemetryService,
5657
playgroundResultViewProvider: PlaygroundResultProvider,
5758
activeConnectionCodeLensProvider: ActiveConnectionCodeLensProvider,
5859
partialExecutionCodeLensProvider: PartialExecutionCodeLensProvider
@@ -63,15 +64,15 @@ export default class EditorsController {
6364
this._playgroundController = playgroundController;
6465
this._context = context;
6566
this._statusView = statusView;
66-
this._telemetryController = telemetryController;
67+
this._telemetryService = telemetryService;
6768
this._memoryFileSystemProvider = new MemoryFileSystemProvider();
6869
this._documentIdStore = new DocumentIdStore();
6970
this._mongoDBDocumentService = new MongoDBDocumentService(
7071
this._context,
7172
this._documentIdStore,
7273
this._connectionController,
7374
this._statusView,
74-
this._telemetryController
75+
this._telemetryService
7576
);
7677
this._collectionViewProvider = new CollectionDocumentsProvider(
7778
connectionController,
@@ -123,8 +124,9 @@ export default class EditorsController {
123124
const connectionIdUriQuery = `${CONNECTION_ID_URI_IDENTIFIER}=${activeConnectionId}`;
124125
const documentIdReference = this._documentIdStore.add(data.documentId);
125126
const documentIdUriQuery = `${DOCUMENT_ID_URI_IDENTIFIER}=${documentIdReference}`;
127+
const documentSourceUriQuery = `${DOCUMENT_SOURCE_URI_IDENTIFIER}=${data.source}`;
126128
const uri: vscode.Uri = vscode.Uri.parse(fileName).with({
127-
query: `?${namespaceUriQuery}&${connectionIdUriQuery}&${documentIdUriQuery}`
129+
query: `?${namespaceUriQuery}&${connectionIdUriQuery}&${documentIdUriQuery}&${documentSourceUriQuery}`
128130
});
129131
const document = await vscode.workspace.openTextDocument(uri);
130132

@@ -154,6 +156,7 @@ export default class EditorsController {
154156
const connectionId = uriParams.get(CONNECTION_ID_URI_IDENTIFIER);
155157
const documentIdReference = uriParams.get(DOCUMENT_ID_URI_IDENTIFIER) || '';
156158
const documentId = this._documentIdStore.get(documentIdReference);
159+
const source = uriParams.get(DOCUMENT_SOURCE_URI_IDENTIFIER) || '';
157160

158161
// If not MongoDB document save to disk instead of MongoDB.
159162
if (
@@ -176,7 +179,8 @@ export default class EditorsController {
176179
namespace,
177180
connectionId,
178181
documentId,
179-
newDocument
182+
newDocument,
183+
source
180184
});
181185

182186
// Save document changes to active editor.

src/editors/mongoDBDocumentService.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import { EJSON } from 'bson';
33
import DocumentIdStore from './documentIdStore';
44
import ConnectionController from '../connectionController';
55
import { StatusView } from '../views';
6-
import TelemetryController from '../telemetry/telemetryController';
6+
import TelemetryService, { DocumentSource } from '../telemetry/telemetryService';
77
import { createLogger } from '../logging';
88
import util from 'util';
99
import type { ResultCodeLensInfo } from '../utils/types';
1010

1111
export const DOCUMENT_ID_URI_IDENTIFIER = 'documentId';
1212

13+
export const DOCUMENT_SOURCE_URI_IDENTIFIER = 'source';
14+
1315
export const VIEW_DOCUMENT_SCHEME = 'VIEW_DOCUMENT_SCHEME';
1416

1517
const log = createLogger('document controller');
@@ -19,20 +21,20 @@ export default class MongoDBDocumentService {
1921
_documentIdStore: DocumentIdStore;
2022
_connectionController: ConnectionController;
2123
_statusView: StatusView;
22-
_telemetryController: TelemetryController;
24+
_telemetryService: TelemetryService;
2325

2426
constructor(
2527
context: vscode.ExtensionContext,
2628
documentIdStore: DocumentIdStore,
2729
connectionController: ConnectionController,
2830
statusView: StatusView,
29-
telemetryController: TelemetryController
31+
telemetryService: TelemetryService
3032
) {
3133
this._context = context;
3234
this._documentIdStore = documentIdStore;
3335
this._connectionController = connectionController;
3436
this._statusView = statusView;
35-
this._telemetryController = telemetryController;
37+
this._telemetryService = telemetryService;
3638
}
3739

3840
_fetchDocumentFailed(message: string): void {
@@ -44,8 +46,9 @@ export default class MongoDBDocumentService {
4446
_saveDocumentFailed(message: string): void {
4547
const errorMessage = `Unable to save document: ${message}`;
4648

47-
// Send a telemetry event that saving the document failed.
48-
this._telemetryController.trackDocumentUpdated('treeview', false);
49+
this._telemetryService.trackDocumentUpdated(
50+
DocumentSource.DOCUMENT_SOURCE_TREEVIEW, false
51+
);
4952

5053
throw new Error(errorMessage);
5154
}
@@ -55,10 +58,11 @@ export default class MongoDBDocumentService {
5558
namespace: string;
5659
connectionId: string;
5760
newDocument: EJSON.SerializableTypes;
61+
source: string;
5862
}): Promise<void> {
5963
log.info('replace document in MongoDB', data);
6064

61-
const { documentId, namespace, connectionId, newDocument } = data;
65+
const { documentId, namespace, connectionId, newDocument, source } = data;
6266
const activeConnectionId = this._connectionController.getActiveConnectionId();
6367
const connectionName = this._connectionController.getSavedConnectionName(
6468
connectionId
@@ -97,11 +101,13 @@ export default class MongoDBDocumentService {
97101
);
98102

99103
this._statusView.hideMessage();
100-
this._telemetryController.trackDocumentUpdated('treeview', true);
104+
this._telemetryService.trackDocumentUpdated(source, true);
101105
} catch (error) {
106+
const printableError = error as { message: string };
107+
102108
this._statusView.hideMessage();
103109

104-
return this._saveDocumentFailed(error.message);
110+
return this._saveDocumentFailed(printableError.message);
105111
}
106112
}
107113

@@ -155,9 +161,11 @@ export default class MongoDBDocumentService {
155161
EJSON.stringify(documents[0])
156162
) as EJSON.SerializableTypes;
157163
} catch (error) {
164+
const printableError = error as { message: string };
165+
158166
this._statusView.hideMessage();
159167

160-
return this._fetchDocumentFailed(error.message);
168+
return this._fetchDocumentFailed(printableError.message);
161169
}
162170
}
163171
}

0 commit comments

Comments
 (0)