Merge pull request #2118 from frappe/mergify/bp/main-hotfix/pr-2117
chore: capture more events for analytics (backport #2117)
This commit is contained in:
@@ -93,11 +93,19 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { createResource, TextEditor, Button, Dropdown, toast } from 'frappe-ui'
|
||||
import {
|
||||
call,
|
||||
createResource,
|
||||
TextEditor,
|
||||
Button,
|
||||
Dropdown,
|
||||
toast,
|
||||
} from 'frappe-ui'
|
||||
import { timeAgo } from '@/utils'
|
||||
import UserAvatar from '@/components/UserAvatar.vue'
|
||||
import { ChevronLeft, MoreHorizontal } from 'lucide-vue-next'
|
||||
import { ref, inject, onMounted, onUnmounted } from 'vue'
|
||||
import { useTelemetry } from 'frappe-ui/frappe'
|
||||
|
||||
const showTopics = defineModel('showTopics')
|
||||
const newReply = ref('')
|
||||
@@ -107,6 +115,7 @@ const allUsers = inject('$allUsers')
|
||||
const mentionUsers = ref([])
|
||||
const renderEditor = ref(false)
|
||||
const readOnlyMode = window.read_only_mode
|
||||
const { capture } = useTelemetry()
|
||||
|
||||
const props = defineProps({
|
||||
topic: {
|
||||
@@ -143,19 +152,6 @@ const replies = createResource({
|
||||
auto: true,
|
||||
})
|
||||
|
||||
const newReplyResource = createResource({
|
||||
url: 'frappe.client.insert',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doc: {
|
||||
doctype: 'Discussion Reply',
|
||||
reply: newReply.value,
|
||||
topic: props.topic.name,
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const fetchMentionUsers = () => {
|
||||
if (user.data?.is_student) {
|
||||
renderEditor.value = true
|
||||
@@ -178,78 +174,61 @@ const fetchMentionUsers = () => {
|
||||
}
|
||||
|
||||
const postReply = () => {
|
||||
newReplyResource.submit(
|
||||
{},
|
||||
{
|
||||
validate() {
|
||||
if (!newReply.value) {
|
||||
return 'Reply cannot be empty'
|
||||
}
|
||||
},
|
||||
onSuccess() {
|
||||
newReply.value = ''
|
||||
replies.reload()
|
||||
},
|
||||
onError(err) {
|
||||
toast.error(err.messages?.[0] || err)
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const editReplyResource = createResource({
|
||||
url: 'frappe.client.set_value',
|
||||
makeParams(values) {
|
||||
return {
|
||||
if (!newReply.value) {
|
||||
toast.error(__('Reply cannot be empty.'))
|
||||
return
|
||||
}
|
||||
call('frappe.client.insert', {
|
||||
doc: {
|
||||
doctype: 'Discussion Reply',
|
||||
name: values.name,
|
||||
fieldname: 'reply',
|
||||
value: values.reply,
|
||||
}
|
||||
},
|
||||
})
|
||||
reply: newReply.value,
|
||||
topic: props.topic.name,
|
||||
},
|
||||
})
|
||||
.then((data) => {
|
||||
newReply.value = ''
|
||||
replies.reload()
|
||||
capture('discussion_reply_created')
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.messages?.[0] || err)
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
const postEdited = (reply) => {
|
||||
editReplyResource.submit(
|
||||
{
|
||||
name: reply.name,
|
||||
reply: reply.reply,
|
||||
},
|
||||
{
|
||||
validate() {
|
||||
if (!reply.reply) {
|
||||
return 'Reply cannot be empty'
|
||||
}
|
||||
},
|
||||
onSuccess() {
|
||||
reply.editable = false
|
||||
replies.reload()
|
||||
},
|
||||
}
|
||||
)
|
||||
if (!reply.reply) {
|
||||
toast.error(__('Reply cannot be empty.'))
|
||||
return
|
||||
}
|
||||
call('frappe.client.set_value', {
|
||||
doctype: 'Discussion Reply',
|
||||
name: reply.name,
|
||||
fieldname: 'reply',
|
||||
value: reply.reply,
|
||||
})
|
||||
.then(() => {
|
||||
reply.editable = false
|
||||
replies.reload()
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.messages?.[0] || err)
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
const deleteReplyResource = createResource({
|
||||
url: 'frappe.client.delete',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doctype: 'Discussion Reply',
|
||||
name: values.name,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const deleteReply = (reply) => {
|
||||
deleteReplyResource.submit(
|
||||
{
|
||||
name: reply.name,
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
replies.reload()
|
||||
},
|
||||
}
|
||||
)
|
||||
call('frappe.client.delete', {
|
||||
doctype: 'Discussion Reply',
|
||||
name: reply.name,
|
||||
})
|
||||
.then(() => {
|
||||
replies.reload()
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.messages?.[0] || err)
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
|
||||
@@ -34,17 +34,13 @@
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import {
|
||||
Dialog,
|
||||
FormControl,
|
||||
TextEditor,
|
||||
createResource,
|
||||
toast,
|
||||
} from 'frappe-ui'
|
||||
import { call, Dialog, FormControl, TextEditor, toast } from 'frappe-ui'
|
||||
import { reactive } from 'vue'
|
||||
import { singularize } from '@/utils'
|
||||
import { useTelemetry } from 'frappe-ui/frappe'
|
||||
|
||||
const topics = defineModel('reloadTopics')
|
||||
const { capture } = useTelemetry()
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
@@ -66,64 +62,50 @@ const topic = reactive({
|
||||
reply: '',
|
||||
})
|
||||
|
||||
const topicResource = createResource({
|
||||
url: 'frappe.client.insert',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doc: {
|
||||
doctype: 'Discussion Topic',
|
||||
reference_doctype: props.doctype,
|
||||
reference_docname: props.docname,
|
||||
title: topic.title,
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const replyResource = createResource({
|
||||
url: 'frappe.client.insert',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doc: {
|
||||
doctype: 'Discussion Reply',
|
||||
topic: values.topic,
|
||||
reply: topic.reply,
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const submitTopic = (close) => {
|
||||
topicResource.submit(
|
||||
{},
|
||||
{
|
||||
validate() {
|
||||
if (!topic.title) {
|
||||
return 'Title cannot be empty.'
|
||||
}
|
||||
if (!topic.reply) {
|
||||
return 'Reply cannot be empty.'
|
||||
}
|
||||
},
|
||||
onSuccess(data) {
|
||||
replyResource.submit(
|
||||
{
|
||||
topic: data.name,
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
topic.title = ''
|
||||
topic.reply = ''
|
||||
topics.value.reload()
|
||||
close()
|
||||
},
|
||||
}
|
||||
)
|
||||
},
|
||||
onError(err) {
|
||||
toast.error(err.messages?.[0] || err)
|
||||
},
|
||||
}
|
||||
)
|
||||
if (!topic.title) {
|
||||
toast.error(__('Title cannot be empty.'))
|
||||
return
|
||||
}
|
||||
if (!topic.reply) {
|
||||
toast.error(__('Details cannot be empty.'))
|
||||
return
|
||||
}
|
||||
call('frappe.client.insert', {
|
||||
doc: {
|
||||
doctype: 'Discussion Topic',
|
||||
reference_doctype: props.doctype,
|
||||
reference_docname: props.docname,
|
||||
title: topic.title,
|
||||
},
|
||||
})
|
||||
.then((data) => {
|
||||
createReply(data.name, close)
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.messages?.[0] || err)
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
const createReply = (topicName, close) => {
|
||||
call('frappe.client.insert', {
|
||||
doc: {
|
||||
doctype: 'Discussion Reply',
|
||||
topic: topicName,
|
||||
reply: topic.reply,
|
||||
},
|
||||
})
|
||||
.then((data) => {
|
||||
topic.title = ''
|
||||
topic.reply = ''
|
||||
topics.value.reload()
|
||||
capture('discussion_topic_created')
|
||||
close()
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(err.messages?.[0] || err)
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -131,6 +131,7 @@ import { ref, watch, reactive, inject } from 'vue'
|
||||
import { RefreshCw, Plus, Search, Shield } from 'lucide-vue-next'
|
||||
import { useOnboarding } from 'frappe-ui/frappe'
|
||||
import type { User } from '@/components/Settings/types'
|
||||
import { useTelemetry } from 'frappe-ui/frappe'
|
||||
|
||||
type Member = {
|
||||
username: string
|
||||
@@ -149,6 +150,7 @@ const hasNextPage = ref(false)
|
||||
const showForm = ref(false)
|
||||
const user = inject<User | null>('$user')
|
||||
const { updateOnboardingStep } = useOnboarding('learning')
|
||||
const { capture } = useTelemetry()
|
||||
|
||||
const member = reactive({
|
||||
email: '',
|
||||
@@ -202,6 +204,7 @@ const addMember = (close: () => void) => {
|
||||
})
|
||||
.then((data: Member) => {
|
||||
if (user?.data?.is_system_manager) updateOnboardingStep('invite_students')
|
||||
capture('user_added')
|
||||
show.value = false
|
||||
router.push({
|
||||
name: 'ProfileRoles',
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<script setup lang="ts">
|
||||
import { Button, Dialog, FormControl, TextEditor, toast } from 'frappe-ui'
|
||||
import { Link, useOnboarding, useTelemetry } from 'frappe-ui/frappe'
|
||||
import { inject, onMounted, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import { inject, onMounted, onBeforeUnmount, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { cleanError, openSettings } from '@/utils'
|
||||
import MultiSelect from '@/components/Controls/MultiSelect.vue'
|
||||
@@ -148,13 +148,13 @@ const keyboardShortcut = (e: KeyboardEvent) => {
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('keydown', keyboardShortcut)
|
||||
capture('course_form_opened')
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', keyboardShortcut)
|
||||
})
|
||||
|
||||
watch(show, () => {
|
||||
if (show.value) capture('course_form_opened')
|
||||
capture('course_form_closed', {
|
||||
data: course.value,
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -103,7 +103,7 @@ def save_progress(lesson: str, course: str, scorm_details: dict = None):
|
||||
)
|
||||
|
||||
progress = get_course_progress(course)
|
||||
capture_progress_for_analytics(progress, course)
|
||||
capture_progress_for_analytics()
|
||||
|
||||
# Had to get doc, as on_change doesn't trigger when you use set_value. The trigger is necessary for badge to get assigned.
|
||||
enrollment = frappe.get_doc("LMS Enrollment", membership)
|
||||
@@ -121,9 +121,8 @@ def save_progress(lesson: str, course: str, scorm_details: dict = None):
|
||||
return progress
|
||||
|
||||
|
||||
def capture_progress_for_analytics(progress, course):
|
||||
if progress in [25, 50, 75, 100]:
|
||||
capture("course_progress", "lms", properties={"course": course, "progress": progress})
|
||||
def capture_progress_for_analytics():
|
||||
capture("course_progress", "lms")
|
||||
|
||||
|
||||
def get_quiz_progress(lesson):
|
||||
|
||||
@@ -18,8 +18,8 @@ class LMSCertificate(Document):
|
||||
self.name = make_autoname("hash", self.doctype)
|
||||
|
||||
def after_insert(self):
|
||||
self.send_certification_email()
|
||||
capture("certificate_issued", "lms")
|
||||
self.send_certification_email()
|
||||
|
||||
def send_certification_email(self):
|
||||
outgoing_email_account = frappe.get_cached_value(
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2026-01-29 16:10:47.787285",
|
||||
"modified": "2026-02-23 16:21:18.503806",
|
||||
"modified_by": "sayali@frappe.io",
|
||||
"module": "LMS",
|
||||
"name": "LMS Course Review",
|
||||
|
||||
Reference in New Issue
Block a user