From 217f61902eb70e081bf41e610aafa9613d1f7077 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 17 Oct 2024 21:23:07 -0700 Subject: [PATCH] add metrics --- extensions/void/package-lock.json | 62 +++++++++++++++++++++ extensions/void/package.json | 2 + extensions/void/src/extension.ts | 9 +++ extensions/void/src/metrics/posthog.tsx | 25 +++++++++ extensions/void/src/shared_types.ts | 2 + extensions/void/src/sidebar/Sidebar.tsx | 18 ++++-- extensions/void/src/sidebar/getVscodeApi.ts | 2 + 7 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 extensions/void/src/metrics/posthog.tsx diff --git a/extensions/void/package-lock.json b/extensions/void/package-lock.json index 79e7526f..a7f8924e 100644 --- a/extensions/void/package-lock.json +++ b/extensions/void/package-lock.json @@ -20,6 +20,7 @@ "@types/node": "^22.5.1", "@types/react": "^18.3.4", "@types/react-dom": "^18.3.0", + "@types/react-syntax-highlighter": "^15.5.13", "@types/uuid": "^10.0.0", "@types/vscode": "1.92.0", "@typescript-eslint/eslint-plugin": "^8.3.0", @@ -36,6 +37,7 @@ "marked": "^14.1.0", "ollama": "^0.5.9", "postcss": "^8.4.41", + "posthog-js": "^1.174.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-markdown": "^9.0.1", @@ -769,6 +771,16 @@ "@types/react": "*" } }, + "node_modules/@types/react-syntax-highlighter": { + "version": "15.5.13", + "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz", + "integrity": "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -1951,6 +1963,18 @@ "dev": true, "license": "MIT" }, + "node_modules/core-js": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz", + "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -2888,6 +2912,13 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/fflate": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==", + "dev": true, + "license": "MIT" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -6313,6 +6344,30 @@ "dev": true, "license": "MIT" }, + "node_modules/posthog-js": { + "version": "1.174.0", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.174.0.tgz", + "integrity": "sha512-60qCn8bloCxVc3oBQ/JP77J40J7UD+cRGUfYXJdsqjUH82s2wmCx4MicuNrcn9Hd2dHM25nXmOAMLO5iwSq9gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-js": "^3.38.1", + "fflate": "^0.4.8", + "preact": "^10.19.3", + "web-vitals": "^4.2.0" + } + }, + "node_modules/preact": { + "version": "10.24.3", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", + "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -8102,6 +8157,13 @@ "node": ">= 14" } }, + "node_modules/web-vitals": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.3.tgz", + "integrity": "sha512-/CFAm1mNxSmOj6i0Co+iGFJ58OS4NRGVP+AWS/l509uIK5a1bSoIVaHz/ZumpHTfHSZBpgrJ+wjfpAOrTHok5Q==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/extensions/void/package.json b/extensions/void/package.json index 78b7a0bb..32d9b22e 100644 --- a/extensions/void/package.json +++ b/extensions/void/package.json @@ -116,6 +116,7 @@ "@types/node": "^22.5.1", "@types/react": "^18.3.4", "@types/react-dom": "^18.3.0", + "@types/react-syntax-highlighter": "^15.5.13", "@types/uuid": "^10.0.0", "@types/vscode": "1.92.0", "@typescript-eslint/eslint-plugin": "^8.3.0", @@ -132,6 +133,7 @@ "marked": "^14.1.0", "ollama": "^0.5.9", "postcss": "^8.4.41", + "posthog-js": "^1.174.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-markdown": "^9.0.1", diff --git a/extensions/void/src/extension.ts b/extensions/void/src/extension.ts index a2724435..46e4266d 100644 --- a/extensions/void/src/extension.ts +++ b/extensions/void/src/extension.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import { DisplayChangesProvider } from './DisplayChangesProvider'; import { BaseDiffArea, ChatThreads, MessageFromSidebar, MessageToSidebar } from './shared_types'; import { SidebarWebviewProvider } from './SidebarWebviewProvider'; +import { v4 as uuidv4 } from 'uuid' const readFileContentOfUri = async (uri: vscode.Uri) => { return Buffer.from(await vscode.workspace.fs.readFile(uri)).toString('utf8') @@ -132,6 +133,14 @@ export function activate(context: vscode.ExtensionContext) { const updatedThreads: ChatThreads = { ...threads, [m.thread.id]: m.thread } context.workspaceState.update('allThreads', updatedThreads) } + else if (m.type === 'getDeviceId') { + let deviceId = context.globalState.get('void_deviceid') + if (!deviceId || typeof deviceId !== 'string') { + deviceId = uuidv4() + context.globalState.update('void_deviceid', deviceId) + } + webview.postMessage({ type: 'deviceId', deviceId: deviceId as string } satisfies MessageToSidebar) + } else { console.error('unrecognized command', m) } diff --git a/extensions/void/src/metrics/posthog.tsx b/extensions/void/src/metrics/posthog.tsx new file mode 100644 index 00000000..b51ce931 --- /dev/null +++ b/extensions/void/src/metrics/posthog.tsx @@ -0,0 +1,25 @@ +import posthog from 'posthog-js' +import { useEffect } from 'react' + + +export const identifyUser = (id: string) => { + posthog.identify(id) +} + +export const captureEvent = (eventId: string, properties: object) => { + posthog.capture(eventId, properties) +} + +export const useMetrics = () => { + // We send absolutely no code to the server. We only track usage metrics like button clicks, etc. This might change and we might eventually add an opt-in or opt-out. + useEffect(() => { + posthog.init('phc_UanIdujHiLp55BkUTjB1AuBXcasVkdqRwgnwRlWESH2', + { + api_host: 'https://us.i.posthog.com', + person_profiles: 'identified_only' // we only track events from identified users. We identify them in Sidebar + } + ) + }, []) + +} + diff --git a/extensions/void/src/shared_types.ts b/extensions/void/src/shared_types.ts index a1e3122e..ad7597df 100644 --- a/extensions/void/src/shared_types.ts +++ b/extensions/void/src/shared_types.ts @@ -47,6 +47,7 @@ type MessageToSidebar = ( | { type: 'startNewThread' } | { type: 'toggleThreadSelector' } | { type: 'toggleSettings' } + | { type: 'deviceId', deviceId: string } ) // sidebar -> editor @@ -57,6 +58,7 @@ type MessageFromSidebar = ( | { type: 'persistPartialVoidConfig', partialVoidConfig: PartialVoidConfig } | { type: 'getAllThreads' } | { type: 'persistThread', thread: ChatThreads[string] } + | { type: 'getDeviceId' } ) diff --git a/extensions/void/src/sidebar/Sidebar.tsx b/extensions/void/src/sidebar/Sidebar.tsx index 36029f01..8986fce9 100644 --- a/extensions/void/src/sidebar/Sidebar.tsx +++ b/extensions/void/src/sidebar/Sidebar.tsx @@ -3,13 +3,24 @@ import { CodeSelection, ChatMessage, MessageToSidebar } from "../shared_types" import { awaitVSCodeResponse, getVSCodeAPI, onMessageFromVSCode, useOnVSCodeMessage } from "./getVscodeApi" import { SidebarThreadSelector } from "./SidebarThreadSelector"; -import { useThreads } from "./contextForThreads"; import { SidebarChat } from "./SidebarChat"; import { SidebarSettings } from './SidebarSettings'; - +import { identifyUser, useMetrics } from "../metrics/posthog"; const Sidebar = () => { + + useMetrics() + + // when we get the deviceid, identify the user + useEffect(() => { + getVSCodeAPI().postMessage({ type: 'getDeviceId' }); + awaitVSCodeResponse('deviceId').then((m => { + identifyUser(m.deviceId) + })) + }, []) + + const [tab, setTab] = useState<'threadSelector' | 'chat' | 'settings'>('chat') // if they pressed the + to add a new chat @@ -33,7 +44,6 @@ const Sidebar = () => { setTab('settings') }) - // Receive messages from the VSCode extension useEffect(() => { const listener = (event: MessageEvent) => { @@ -61,8 +71,6 @@ const Sidebar = () => { - - diff --git a/extensions/void/src/sidebar/getVscodeApi.ts b/extensions/void/src/sidebar/getVscodeApi.ts index 80f29ff0..4da06d46 100644 --- a/extensions/void/src/sidebar/getVscodeApi.ts +++ b/extensions/void/src/sidebar/getVscodeApi.ts @@ -14,6 +14,7 @@ const onetimeCallbacks: { [C in Command]: ((res: any) => void)[] } = { "allThreads": [], "toggleThreadSelector": [], "toggleSettings": [], + "deviceId": [], } // messageType -> id -> res @@ -25,6 +26,7 @@ const callbacks: { [C in Command]: { [id: string]: ((res: any) => void) } } = { "allThreads": {}, "toggleThreadSelector": {}, "toggleSettings": {}, + "deviceId": {} }