From a439433977321188266ff38cdef09642e4166080 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Fri, 16 Aug 2024 17:27:12 +0530 Subject: [PATCH] feat: Init posthog telemetry to analyse crm usage --- crm/api/__init__.py | 12 ++++- frontend/src/main.js | 15 +++--- frontend/src/telemetry.ts | 97 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 frontend/src/telemetry.ts diff --git a/crm/api/__init__.py b/crm/api/__init__.py index 533a30c0..f0909118 100644 --- a/crm/api/__init__.py +++ b/crm/api/__init__.py @@ -2,6 +2,7 @@ from bs4 import BeautifulSoup import frappe from frappe.translate import get_all_translations from frappe.utils import cstr +from frappe.utils.telemetry import POSTHOG_HOST_FIELD, POSTHOG_PROJECT_FIELD @frappe.whitelist(allow_guest=True) @@ -44,4 +45,13 @@ def get_user_signature(): content = "" if (cstr(_signature) or signature): content = f'

{signature}

' - return content \ No newline at end of file + return content + +@frappe.whitelist() +def get_posthog_settings(): + return { + "posthog_project_id": frappe.conf.get(POSTHOG_PROJECT_FIELD), + "posthog_host": frappe.conf.get(POSTHOG_HOST_FIELD), + "enable_telemetry": frappe.get_system_settings("enable_telemetry"), + "telemetry_site_age": frappe.utils.telemetry.site_age(), + } \ No newline at end of file diff --git a/frontend/src/main.js b/frontend/src/main.js index 66d44ea2..b0209480 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -1,10 +1,5 @@ import './index.css' -import { createApp } from 'vue' -import router from './router' -import App from './App.vue' -import { createPinia } from 'pinia' - import { FrappeUI, Button, @@ -19,9 +14,14 @@ import { frappeRequest, FeatherIcon, } from 'frappe-ui' -import translationPlugin from './translation' +import { createApp } from 'vue' +import { createPinia } from 'pinia' import { createDialog } from './utils/dialogs' import { initSocket } from './socket' +import router from './router' +import translationPlugin from './translation' +import { posthogPlugin } from './telemetry' +import App from './App.vue' let globalComponents = { Button, @@ -45,6 +45,7 @@ app.use(FrappeUI) app.use(pinia) app.use(router) app.use(translationPlugin) +app.use(posthogPlugin) for (let key in globalComponents) { app.component(key, globalComponents[key]) } @@ -61,7 +62,7 @@ if (import.meta.env.DEV) { socket = initSocket() app.config.globalProperties.$socket = socket app.mount('#app') - } + }, ) } else { socket = initSocket() diff --git a/frontend/src/telemetry.ts b/frontend/src/telemetry.ts new file mode 100644 index 00000000..e77d8a36 --- /dev/null +++ b/frontend/src/telemetry.ts @@ -0,0 +1,97 @@ +import '../../../frappe/frappe/public/js/lib/posthog.js' +import { createResource } from 'frappe-ui' +import { computed } from 'vue' + +declare global { + interface Window { + posthog: any + } +} +type PosthogSettings = { + posthog_project_id: string + posthog_host: string + enable_telemetry: boolean + telemetry_site_age: number +} +interface CaptureOptions { + data: { + user: string + [key: string]: string | number | boolean | object + } +} + +let posthog: typeof window.posthog = window.posthog + +// Posthog Settings +let posthogSettings = createResource({ + url: 'crm.api.get_posthog_settings', + cache: 'posthog_settings', + onSuccess: (ps: PosthogSettings) => initPosthog(ps), +}) + +let isTelemetryEnabled = () => { + if (!posthogSettings.data) return false + + return ( + posthogSettings.data.enable_telemetry && + posthogSettings.data.posthog_project_id && + posthogSettings.data.posthog_host + ) +} + +// Posthog Initialization +function initPosthog(ps: PosthogSettings) { + if (!isTelemetryEnabled()) return + + posthog.init(ps.posthog_project_id, { + api_host: ps.posthog_host, + person_profiles: 'identified_only', + autocapture: false, + capture_pageview: false, + capture_pageleave: false, + enable_heatmaps: false, + disable_session_recording: true, + loaded: (ph: typeof posthog) => { + window.posthog = ph + ph.identify(window.location.host) + }, + }) +} + +// Posthog Functions +function capture( + event: string, + options: CaptureOptions = { data: { user: '' } }, +) { + if (!isTelemetryEnabled()) return + window.posthog.capture(`crm_${event}`, options) +} + +function startRecording() { + if (!isTelemetryEnabled()) return + if (window.posthog?.__loaded) { + window.posthog.startSessionRecording() + } +} + +function stopRecording() { + if (!isTelemetryEnabled()) return + if (window.posthog?.__loaded && window.posthog.sessionRecordingStarted()) { + window.posthog.stopSessionRecording() + } +} + +// Posthog Plugin +function posthogPlugin(app: any) { + app.config.globalProperties.posthog = posthog + if (!window.posthog?.length) posthogSettings.fetch() +} + +export { + posthog, + posthogSettings, + posthogPlugin, + capture, + startRecording, + stopRecording, +}