diff --git a/desk/src/pages/onboarding/OnboardingIntro.vue b/desk/src/pages/onboarding/OnboardingIntro.vue index c46f3f0ab..14145fac9 100644 --- a/desk/src/pages/onboarding/OnboardingIntro.vue +++ b/desk/src/pages/onboarding/OnboardingIntro.vue @@ -10,10 +10,15 @@ diff --git a/desk/src/pages/onboarding/SetupFavicon.vue b/desk/src/pages/onboarding/SetupFavicon.vue index dff1e4177..c3b930df8 100644 --- a/desk/src/pages/onboarding/SetupFavicon.vue +++ b/desk/src/pages/onboarding/SetupFavicon.vue @@ -21,8 +21,9 @@ diff --git a/desk/src/pages/onboarding/SetupLogo.vue b/desk/src/pages/onboarding/SetupLogo.vue index cccf9a43f..c264c7db7 100644 --- a/desk/src/pages/onboarding/SetupLogo.vue +++ b/desk/src/pages/onboarding/SetupLogo.vue @@ -21,8 +21,9 @@ diff --git a/desk/src/pages/onboarding/SetupName.vue b/desk/src/pages/onboarding/SetupName.vue index beac3f8e6..5dd02c1d6 100644 --- a/desk/src/pages/onboarding/SetupName.vue +++ b/desk/src/pages/onboarding/SetupName.vue @@ -20,8 +20,9 @@ diff --git a/desk/src/pages/onboarding/SetupSkipEmail.vue b/desk/src/pages/onboarding/SetupSkipEmail.vue index 69a21cd27..1215fc5e1 100644 --- a/desk/src/pages/onboarding/SetupSkipEmail.vue +++ b/desk/src/pages/onboarding/SetupSkipEmail.vue @@ -10,8 +10,9 @@ diff --git a/desk/src/pages/onboarding/SuccessMessage.vue b/desk/src/pages/onboarding/SuccessMessage.vue index 53294fa16..cd6b39544 100644 --- a/desk/src/pages/onboarding/SuccessMessage.vue +++ b/desk/src/pages/onboarding/SuccessMessage.vue @@ -32,8 +32,13 @@ diff --git a/desk/src/pages/onboarding/email/EmailCredentials.vue b/desk/src/pages/onboarding/email/EmailCredentials.vue index 4c61e63f2..47b410d16 100644 --- a/desk/src/pages/onboarding/email/EmailCredentials.vue +++ b/desk/src/pages/onboarding/email/EmailCredentials.vue @@ -34,9 +34,10 @@ diff --git a/desk/src/pages/onboarding/email/SelectService.vue b/desk/src/pages/onboarding/email/SelectService.vue index 1516a2615..9c409544f 100644 --- a/desk/src/pages/onboarding/email/SelectService.vue +++ b/desk/src/pages/onboarding/email/SelectService.vue @@ -38,10 +38,11 @@ diff --git a/desk/src/pages/onboarding/email/SetupEmail.vue b/desk/src/pages/onboarding/email/SetupEmail.vue index eb61940db..8af36829a 100644 --- a/desk/src/pages/onboarding/email/SetupEmail.vue +++ b/desk/src/pages/onboarding/email/SetupEmail.vue @@ -5,7 +5,9 @@ diff --git a/desk/src/pages/onboarding/email/SuccessMessage.vue b/desk/src/pages/onboarding/email/SuccessMessage.vue index 28fe72d4c..aff318395 100644 --- a/desk/src/pages/onboarding/email/SuccessMessage.vue +++ b/desk/src/pages/onboarding/email/SuccessMessage.vue @@ -10,8 +10,13 @@ diff --git a/desk/src/router.js b/desk/src/router.js index 625d5b8e2..63ed1bdc5 100644 --- a/desk/src/router.js +++ b/desk/src/router.js @@ -1,6 +1,7 @@ import { createRouter, createWebHistory } from "vue-router"; import { call } from "frappe-ui"; import { useAuthStore } from "@/stores/auth"; +import { init as initTelemetry } from "./telemetry"; export const WEBSITE_ROOT = "Website Root"; @@ -393,6 +394,8 @@ router.beforeEach(async (to) => { }); router.beforeEach(async (to) => { + await initTelemetry(); + const isAuthRoute = AUTH_ROUTES.includes(to.name); const authStore = useAuthStore(); diff --git a/desk/src/telemetry.ts b/desk/src/telemetry.ts new file mode 100644 index 000000000..9a32f929b --- /dev/null +++ b/desk/src/telemetry.ts @@ -0,0 +1,57 @@ +import { useStorage } from "@vueuse/core"; +import { call } from "frappe-ui"; +import "../../../frappe/frappe/public/js/lib/posthog.js"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +declare const posthog: any; + +const APP = "helpdesk"; +const SITENAME = window.location.hostname; + +const telemetry = useStorage("telemetry", { + enabled: false, + project_id: "", + host: "", +}); + +export async function init() { + await set_enabled(); + if (!telemetry.value.enabled) return; + try { + await set_credentials(); + posthog.init(telemetry.value.project_id, { + api_host: telemetry.value.host, + autocapture: false, + capture_pageview: false, + capture_pageleave: false, + advanced_disable_decide: true, + }); + posthog.identify(SITENAME); + } catch (e) { + console.trace("Failed to initialize telemetry", e); + telemetry.value.enabled = false; + } +} + +async function set_enabled() { + if (telemetry.value.enabled) return; + + await call("helpdesk.api.telemetry.is_enabled").then((res) => { + telemetry.value.enabled = res; + }); +} + +async function set_credentials() { + if (!telemetry.value.enabled) return; + if (telemetry.value.project_id && telemetry.value.host) return; + + await call("helpdesk.api.telemetry.get_credentials").then((res) => { + telemetry.value.project_id = res.project_id; + telemetry.value.host = res.telemetry_host; + }); +} + +export function capture(event: string) { + if (!telemetry.value.enabled) return; + posthog.capture(`${APP}_${event}`); +} diff --git a/helpdesk/api/telemetry.py b/helpdesk/api/telemetry.py new file mode 100644 index 000000000..7fd31a3e0 --- /dev/null +++ b/helpdesk/api/telemetry.py @@ -0,0 +1,18 @@ +import frappe + + +@frappe.whitelist() +def is_enabled(): + return bool( + frappe.get_system_settings("enable_telemetry") + and frappe.conf.get("posthog_host") + and frappe.conf.get("posthog_project_id") + ) + + +@frappe.whitelist() +def get_credentials(): + return { + "project_id": frappe.conf.get("posthog_project_id"), + "telemetry_host": frappe.conf.get("posthog_host"), + } diff --git a/helpdesk/helpdesk/doctype/hd_ticket/hd_ticket.py b/helpdesk/helpdesk/doctype/hd_ticket/hd_ticket.py index 690887ae2..4df90fe27 100644 --- a/helpdesk/helpdesk/doctype/hd_ticket/hd_ticket.py +++ b/helpdesk/helpdesk/doctype/hd_ticket/hd_ticket.py @@ -16,7 +16,6 @@ from frappe.model.mapper import get_mapped_doc from frappe.query_builder import Case, DocType, Order from frappe.query_builder.functions import Count -from frappe.realtime import get_website_room from frappe.utils import date_diff, get_datetime, now_datetime, time_diff_in_seconds from frappe.utils.user import is_website_user @@ -27,8 +26,7 @@ default_outgoing_email_account, default_ticket_outgoing_email_account, ) - -from helpdesk.utils import publish_event +from helpdesk.utils import publish_event, capture_event class HDTicket(Document): @@ -439,6 +437,8 @@ def reply_via_agent( self.status = "Replied" self.save() + capture_event("agent_replied") + if skip_email_workflow: return diff --git a/helpdesk/utils.py b/helpdesk/utils.py index 14cb992b9..d6ffd57f9 100644 --- a/helpdesk/utils.py +++ b/helpdesk/utils.py @@ -3,6 +3,7 @@ import frappe from bs4 import BeautifulSoup from frappe.realtime import get_website_room +from frappe.utils.telemetry import capture as _capture def publish_event(event: str, data: dict): @@ -10,6 +11,10 @@ def publish_event(event: str, data: dict): frappe.publish_realtime(event, message=data, room=room, after_commit=True) +def capture_event(event: str): + return _capture(event, "helpdesk") + + def extract_mentions(html): if not html: return []