diff --git a/.github/workflows/generate-pot-file.yml b/.github/workflows/generate-pot-file.yml
index 390393d7..4c5d81e1 100644
--- a/.github/workflows/generate-pot-file.yml
+++ b/.github/workflows/generate-pot-file.yml
@@ -5,7 +5,7 @@ on:
workflow_dispatch:
jobs:
- regeneratee-pot-file:
+ regenerate-pot-file:
name: Release
runs-on: ubuntu-latest
strategy:
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 6a9d4d5b..e7dfc8dc 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -8,10 +8,12 @@
diff --git a/frontend/src/components/BatchOverlay.vue b/frontend/src/components/BatchOverlay.vue
index 2eb225c2..670548a4 100644
--- a/frontend/src/components/BatchOverlay.vue
+++ b/frontend/src/components/BatchOverlay.vue
@@ -81,7 +81,7 @@
diff --git a/frontend/src/pages/CreateCourse.vue b/frontend/src/pages/CourseForm.vue
similarity index 98%
rename from frontend/src/pages/CreateCourse.vue
rename to frontend/src/pages/CourseForm.vue
index dbd33dda..9f7f2935 100644
--- a/frontend/src/pages/CreateCourse.vue
+++ b/frontend/src/pages/CourseForm.vue
@@ -227,6 +227,7 @@ import { FileText, X } from 'lucide-vue-next'
import { useRouter } from 'vue-router'
import CourseOutline from '@/components/CourseOutline.vue'
import MultiSelect from '@/components/Controls/MultiSelect.vue'
+import { capture } from '@/telemetry'
const user = inject('$user')
const newTag = ref('')
@@ -268,6 +269,8 @@ onMounted(() => {
if (props.courseName !== 'new') {
courseResource.reload()
+ } else {
+ capture('course_form_opened')
}
window.addEventListener('keydown', keyboardShortcut)
})
@@ -388,9 +391,10 @@ const submitCourse = () => {
} else {
courseCreationResource.submit(course, {
onSuccess(data) {
+ capture('course_created')
showToast('Success', 'Course created successfully', 'check')
router.push({
- name: 'CreateCourse',
+ name: 'CourseForm',
params: { courseName: data.name },
})
},
@@ -489,7 +493,7 @@ const breadcrumbs = computed(() => {
}
crumbs.push({
label: props.courseName == 'new' ? 'New Course' : 'Edit Course',
- route: { name: 'CreateCourse', params: { courseName: props.courseName } },
+ route: { name: 'CourseForm', params: { courseName: props.courseName } },
})
return crumbs
})
diff --git a/frontend/src/pages/Courses.vue b/frontend/src/pages/Courses.vue
index c367d151..299cf434 100644
--- a/frontend/src/pages/Courses.vue
+++ b/frontend/src/pages/Courses.vue
@@ -22,7 +22,7 @@
{
+ window.posthog = posthog;
+ window.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("lms.lms.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("lms.lms.telemetry.get_credentials").then((res) => {
+ telemetry.value.project_id = res.project_id;
+ telemetry.value.host = res.telemetry_host;
+ });
+}
+
+interface CaptureOptions {
+ data: {
+ user: string;
+ [key: string]: string | number | boolean | object;
+ };
+}
+
+export function capture(
+ event: string,
+ options: CaptureOptions = { data: { user: "" } }
+) {
+ if (!telemetry.value.enabled) return;
+ window.posthog.capture(`${APP}_${event}`, options);
+}
+
+export function recordSession() {
+ if (!telemetry.value.enabled) return;
+ if (window.posthog && window.posthog.__loaded) {
+ window.posthog.startSessionRecording();
+ }
+}
+
+export function stopSession() {
+ if (!telemetry.value.enabled) return;
+ if (
+ window.posthog &&
+ window.posthog.__loaded &&
+ window.posthog.sessionRecordingStarted()
+ ) {
+ window.posthog.stopSessionRecording();
+ }
+}
diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js
index e732e09f..2123d981 100644
--- a/frontend/src/utils/index.js
+++ b/frontend/src/utils/index.js
@@ -424,7 +424,7 @@ export function getSidebarLinks() {
'Courses',
'CourseDetail',
'Lesson',
- 'CreateCourse',
+ 'CourseForm',
'LessonForm',
],
},
@@ -432,7 +432,7 @@ export function getSidebarLinks() {
label: 'Batches',
icon: 'Users',
to: 'Batches',
- activeFor: ['Batches', 'BatchDetail', 'Batch', 'BatchCreation'],
+ activeFor: ['Batches', 'BatchDetail', 'Batch', 'BatchForm'],
},
{
label: 'Certified Participants',
diff --git a/lms/lms/api.py b/lms/lms/api.py
index 67300c13..c25e49da 100644
--- a/lms/lms/api.py
+++ b/lms/lms/api.py
@@ -6,6 +6,7 @@ from frappe.translate import get_all_translations
from frappe import _
from frappe.query_builder import DocType
from frappe.query_builder.functions import Count
+from frappe.utils import time_diff, now_datetime, get_datetime
@frappe.whitelist()
diff --git a/lms/lms/telemetry.py b/lms/lms/telemetry.py
new file mode 100644
index 00000000..7e4de8ec
--- /dev/null
+++ b/lms/lms/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/yarn.lock b/yarn.lock
index 415d00a2..693509b7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -107,7 +107,7 @@ asn1@~0.2.3:
dependencies:
safer-buffer "~2.1.0"
-assert-plus@^1.0.0, assert-plus@1.0.0:
+assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==
@@ -294,7 +294,7 @@ concat-stream@^1.4.7:
readable-stream "^2.2.2"
typedarray "^0.0.6"
-core-util-is@~1.0.0, core-util-is@1.0.2:
+core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==
@@ -322,7 +322,7 @@ cypress-file-upload@^5.0.8:
resolved "https://registry.npmjs.org/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz"
integrity sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g==
-cypress@^13.9.0, cypress@>3.0.0:
+cypress@^13.9.0:
version "13.9.0"
resolved "https://registry.npmjs.org/cypress/-/cypress-13.9.0.tgz"
integrity sha512-atNjmYfHsvTuCaxTxLZr9xGoHz53LLui3266WWxXJHY7+N6OdwJdg/feEa3T+buez9dmUXHT1izCOklqG82uCQ==
@@ -430,7 +430,7 @@ end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
-enquirer@^2.3.6, "enquirer@>= 2.3.0 < 3":
+enquirer@^2.3.6:
version "2.4.1"
resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz"
integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==
@@ -498,16 +498,16 @@ extract-zip@2.0.1:
optionalDependencies:
"@types/yauzl" "^2.9.1"
-extsprintf@^1.2.0:
- version "1.4.1"
- resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz"
- integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
-
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz"
integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==
+extsprintf@^1.2.0:
+ version "1.4.1"
+ resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz"
+ integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
+
fd-slicer@~1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz"
@@ -515,6 +515,11 @@ fd-slicer@~1.1.0:
dependencies:
pend "~1.2.0"
+fflate@^0.4.8:
+ version "0.4.8"
+ resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae"
+ integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==
+
figures@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz"
@@ -836,16 +841,16 @@ minimist@^1.2.8:
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
-ms@^2.1.1:
- version "2.1.3"
- resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
- integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-
ms@2.1.2:
version "2.1.2"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
npm-run-path@^4.0.0:
version "4.0.1"
resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz"
@@ -909,6 +914,15 @@ pify@^2.2.0:
resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz"
integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
+posthog-js@^1.154.4:
+ version "1.154.4"
+ resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.154.4.tgz#217524e45f7ceb68a268caf683da60dfa91eccbd"
+ integrity sha512-J6SvhjNGOqkL8uH/sL3h4rXN7bUz9MnCJ1bu/D9Vkf6Enft8LlkOnzackUwR8EpKdM/dhA0dUjDk5Fz/6dovbw==
+ dependencies:
+ fflate "^0.4.8"
+ preact "^10.19.3"
+ web-vitals "^4.0.1"
+
pre-commit@^1.2.2:
version "1.2.2"
resolved "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz"
@@ -918,6 +932,11 @@ pre-commit@^1.2.2:
spawn-sync "^1.0.15"
which "1.2.x"
+preact@^10.19.3:
+ version "10.23.1"
+ resolved "https://registry.yarnpkg.com/preact/-/preact-10.23.1.tgz#d400107289bc979881c5212cb5f5cd22cd1dc38c"
+ integrity sha512-O5UdRsNh4vdZaTieWe3XOgSpdMAmkIYBCT3VhQDlKrzyCm8lUYsk0fmVEvoQQifoOjFRTaHZO69ylrzTW2BH+A==
+
pretty-bytes@^5.6.0:
version "5.6.0"
resolved "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz"
@@ -1023,12 +1042,7 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.2:
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
-safe-buffer@~5.1.0:
- version "5.1.2"
- resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
- integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-safe-buffer@~5.1.1:
+safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
@@ -1135,13 +1149,6 @@ sshpk@^1.14.1:
safer-buffer "^2.0.2"
tweetnacl "~0.14.0"
-string_decoder@~1.1.1:
- version "1.1.1"
- resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
- integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
- dependencies:
- safe-buffer "~5.1.0"
-
string-width@^4.1.0, string-width@^4.2.0:
version "4.2.3"
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
@@ -1151,6 +1158,13 @@ string-width@^4.1.0, string-width@^4.2.0:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
+string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
+
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
@@ -1276,7 +1290,12 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
-which@^1.2.9, which@1.2.x:
+web-vitals@^4.0.1:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-4.2.2.tgz#e883245180b95e175eb75a5ca8903b1a11597d7a"
+ integrity sha512-nYfoOqb4EmElljyXU2qdeE76KsvoHdftQKY4DzA9Aw8DervCg2bG634pHLrJ/d6+B4mE3nWTSJv8Mo7B2mbZkw==
+
+which@1.2.x, which@^1.2.9:
version "1.2.14"
resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz"
integrity sha512-16uPglFkRPzgiUXYMi1Jf8Z5EzN1iB4V0ZtMXcHZnwsBtQhhHeCqoWw7tsUY42hJGNDWtUsVLTjakIa5BgAxCw==