From b58d04c7dcefc05fe37d74f8c01075e47445a8ee Mon Sep 17 00:00:00 2001 From: raizasafeel <89463672+raizasafeel@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:56:07 +0530 Subject: [PATCH 01/21] feat(batch): add load more pagination for batch students --- frontend/src/components/BatchStudents.vue | 73 ++++++++++++++--------- lms/lms/utils.py | 19 +++++- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/frontend/src/components/BatchStudents.vue b/frontend/src/components/BatchStudents.vue index d6e336a8..26665db5 100644 --- a/frontend/src/components/BatchStudents.vue +++ b/frontend/src/components/BatchStudents.vue @@ -2,7 +2,7 @@
- {{ students.data?.length }} {{ __('Students') }} + {{ studentCount.data ?? 0 }} {{ __('Students') }}
-
-
- {{ __('Course Image') }} -
- - - -
-
- -
- -
- {{ - __('Appears on the course card in the course list') - }} -
-
-
-
-
+ ({ instructor: instructor, })), @@ -471,7 +423,7 @@ const courseEditResource = createResource({ doctype: 'LMS Course', name: values.course, fieldname: { - image: course.course_image?.file_url || '', + image: course.image, instructors: instructors.value.map((instructor) => ({ instructor: instructor, })), @@ -521,24 +473,10 @@ const courseResource = createResource({ course[key] = course[key] ? true : false } - if (data.image) imageResource.reload({ image: data.image }) check_permission() }, }) -const imageResource = createResource({ - url: 'lms.lms.api.get_file_info', - makeParams(values) { - return { - file_url: values.image, - } - }, - auto: false, - onSuccess(data) { - course.course_image = data - }, -}) - const validateFields = () => { course.description = sanitizeHTML(course.description) @@ -655,14 +593,6 @@ const removeTag = (tag) => { newTag.value = '' } -const saveImage = (file) => { - course.course_image = file -} - -const removeImage = () => { - course.course_image = null -} - const check_permission = () => { let user_is_instructor = false if (user.data?.is_moderator) return diff --git a/frontend/src/pages/JobForm.vue b/frontend/src/pages/JobForm.vue index c81d5c62..3b850371 100644 --- a/frontend/src/pages/JobForm.vue +++ b/frontend/src/pages/JobForm.vue @@ -83,47 +83,11 @@ class="mb-4" :required="true" /> - - - - -
-
-
- -
-
- - {{ job.image.file_name }} - - - {{ getFileSize(job.image.file_size) }} - -
- -
-
+
@@ -150,15 +114,14 @@ import { createResource, Button, TextEditor, - FileUploader, usePageMeta, toast, } from 'frappe-ui' import { computed, onMounted, reactive, inject } from 'vue' -import { FileText, X } from 'lucide-vue-next' import { sessionStore } from '@/stores/session' import { useRouter } from 'vue-router' -import { escapeHTML, getFileSize, sanitizeHTML, validateFile } from '@/utils' +import { escapeHTML, sanitizeHTML } from '@/utils' +import Uploader from '@/components/Controls/Uploader.vue' const user = inject('$user') const router = useRouter() @@ -177,7 +140,7 @@ const newJob = createResource({ return { doc: { doctype: 'Job Opportunity', - company_logo: job.image?.file_url, + company_logo: job.company_logo, ...job, }, } @@ -191,7 +154,7 @@ const updateJob = createResource({ doctype: 'Job Opportunity', name: props.jobName, fieldname: { - company_logo: job.image.file_url, + company_logo: job.company_logo, ...job, }, } @@ -215,20 +178,6 @@ const jobDetail = createResource({ Object.keys(data).forEach((key) => { if (Object.hasOwn(job, key)) job[key] = data[key] }) - if (data.company_logo) imageResource.reload({ image: data.company_logo }) - }, -}) - -const imageResource = createResource({ - url: 'lms.lms.api.get_file_info', - makeParams(values) { - return { - file_url: values.image, - } - }, - auto: false, - onSuccess(data) { - job.image = data }, }) @@ -241,7 +190,7 @@ const job = reactive({ status: 'Open', company_name: '', company_website: '', - image: null, + company_logo: null, description: '', company_email_address: '', }) @@ -322,14 +271,6 @@ const validateJobFields = () => { }) } -const saveImage = (file) => { - job.image = file -} - -const removeImage = () => { - job.image = null -} - const jobTypes = computed(() => { return [ { label: 'Full Time', value: 'Full Time' }, From 02564b2e77e0b926d767aaca85df7f7741334f40 Mon Sep 17 00:00:00 2001 From: Jannat Patel <31363128+pateljannat@users.noreply.github.com> Date: Thu, 15 Jan 2026 01:14:08 +0530 Subject: [PATCH 06/21] chore: Russian translations --- lms/locale/ru.po | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lms/locale/ru.po b/lms/locale/ru.po index 278312e2..b9b4ca9a 100644 --- a/lms/locale/ru.po +++ b/lms/locale/ru.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n" "POT-Creation-Date: 2026-01-13 05:34+0000\n" -"PO-Revision-Date: 2026-01-13 19:44\n" +"PO-Revision-Date: 2026-01-14 19:44\n" "Last-Translator: jannat@frappe.io\n" "Language-Team: Russian\n" "MIME-Version: 1.0\n" @@ -2412,7 +2412,7 @@ msgstr "Регистрация на программу {0}" #. Label of the enrollment_from_batch (Link) field in DocType 'LMS Enrollment' #: lms/lms/doctype/lms_enrollment/lms_enrollment.json msgid "Enrollment from Batch" -msgstr "" +msgstr "Зачисление из группы" #: lms/lms/doctype/lms_batch_enrollment/lms_batch_enrollment.py:57 msgid "Enrollment in this batch is restricted. Please contact the Administrator." @@ -2730,7 +2730,7 @@ msgstr "Тип файла" #: frontend/src/components/AssessmentPlugin.vue:54 msgid "Filter assignments by course" -msgstr "" +msgstr "Фильтруйте задания по курсу" #: frontend/src/components/Settings/Transactions/TransactionList.vue:15 msgid "Filter by Billing Name" @@ -3031,7 +3031,7 @@ msgstr "Подсвеченный текст" #: frontend/src/pages/CertifiedParticipants.vue:52 #: frontend/src/pages/Profile.vue:70 lms/fixtures/custom_field.json msgid "Hiring" -msgstr "" +msgstr "Набор персонала" #: frontend/src/pages/Home/Home.vue:5 frontend/src/pages/Home/Home.vue:154 msgid "Home" @@ -3062,7 +3062,7 @@ msgstr "Я недоступен" #: frontend/src/pages/Billing.vue:181 msgid "I consent to my personal information being stored for invoicing" -msgstr "" +msgstr "Я даю согласие на хранение моих персональных данных для выставления счетов" #: frontend/src/pages/QuizForm.vue:340 msgid "ID" @@ -3900,7 +3900,7 @@ msgstr "Самая длинная серия" #: frontend/src/components/Modals/EditProfile.vue:95 msgid "Looking for new work or hiring talent?" -msgstr "" +msgstr "Ищете новую работу или нанимаете талантливых сотрудников?" #: lms/templates/emails/payment_reminder.html:23 msgid "Looking forward to seeing you enrolled!" @@ -4065,7 +4065,7 @@ msgstr "Участник" #. Label of the member_consent (Check) field in DocType 'LMS Payment' #: lms/lms/doctype/lms_payment/lms_payment.json msgid "Member Consent" -msgstr "" +msgstr "Согласие участника" #. Label of the member_count (Int) field in DocType 'LMS Program' #: lms/lms/doctype/lms_program/lms_program.json @@ -4696,7 +4696,7 @@ msgstr "Откройте " #: frontend/src/components/Modals/EditProfile.vue:94 #: lms/fixtures/custom_field.json msgid "Open to" -msgstr "" +msgstr "Открыто для" #: frontend/src/components/UserAvatar.vue:11 #: frontend/src/pages/CertifiedParticipants.vue:46 @@ -5054,7 +5054,7 @@ msgstr "Запишитесь на этот курс, чтобы просмотр #: frontend/src/pages/Billing.vue:99 msgid "Please ensure that the billing name you enter is correct, as it will be used on your invoice." -msgstr "" +msgstr "Пожалуйста, убедитесь, что указанное вами имя плательщика верное, так как оно будет использовано в вашем счете." #: frontend/src/components/Quiz.vue:16 msgid "Please ensure that you complete all the questions in {0} minutes." @@ -5132,11 +5132,11 @@ msgstr "Пожалуйста, хорошо подготовьтесь и при #: frontend/src/pages/Billing.vue:194 msgid "Please provide your consent to proceed with the payment" -msgstr "" +msgstr "Пожалуйста, подтвердите свое согласие на продолжение оплаты" #: frontend/src/pages/Billing.vue:337 msgid "Please provide your consent to proceed with the payment." -msgstr "" +msgstr "Пожалуйста, подтвердите свое согласие на продолжение оплаты." #: frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue:139 msgid "Please run the code to execute the test cases." @@ -5989,7 +5989,7 @@ msgstr "Выберите тест" #: frontend/src/components/AssessmentPlugin.vue:41 #: frontend/src/components/AssessmentPlugin.vue:49 msgid "Select an Assignment" -msgstr "" +msgstr "Выберите задание" #: frontend/src/components/ContactUsEmail.vue:33 #: frontend/src/pages/JobApplications.vue:115 @@ -7796,7 +7796,7 @@ msgstr "{0} не найден" #: frontend/src/pages/Jobs.vue:33 msgid "{0} {1} Jobs" -msgstr "" +msgstr "{0} {1} Работа" #. Count format of shortcut in the LMS Workspace #: lms/lms/workspace/lms/lms.json From de13c5ddfb913cbf655f2c8023f42cd4c277055e Mon Sep 17 00:00:00 2001 From: Jannat Patel <31363128+pateljannat@users.noreply.github.com> Date: Thu, 15 Jan 2026 01:14:11 +0530 Subject: [PATCH 07/21] chore: Serbian (Cyrillic) translations --- lms/locale/sr.po | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lms/locale/sr.po b/lms/locale/sr.po index 481be63b..679ffabe 100644 --- a/lms/locale/sr.po +++ b/lms/locale/sr.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n" "POT-Creation-Date: 2026-01-13 05:34+0000\n" -"PO-Revision-Date: 2026-01-13 19:44\n" +"PO-Revision-Date: 2026-01-14 19:44\n" "Last-Translator: jannat@frappe.io\n" "Language-Team: Serbian (Cyrillic)\n" "MIME-Version: 1.0\n" @@ -2412,7 +2412,7 @@ msgstr "Упис у програм {0}" #. Label of the enrollment_from_batch (Link) field in DocType 'LMS Enrollment' #: lms/lms/doctype/lms_enrollment/lms_enrollment.json msgid "Enrollment from Batch" -msgstr "" +msgstr "Упис из групе" #: lms/lms/doctype/lms_batch_enrollment/lms_batch_enrollment.py:57 msgid "Enrollment in this batch is restricted. Please contact the Administrator." @@ -2730,7 +2730,7 @@ msgstr "Врста фајла" #: frontend/src/components/AssessmentPlugin.vue:54 msgid "Filter assignments by course" -msgstr "" +msgstr "Филтрирај задатке према обуци" #: frontend/src/components/Settings/Transactions/TransactionList.vue:15 msgid "Filter by Billing Name" @@ -3031,7 +3031,7 @@ msgstr "Истакнути текст" #: frontend/src/pages/CertifiedParticipants.vue:52 #: frontend/src/pages/Profile.vue:70 lms/fixtures/custom_field.json msgid "Hiring" -msgstr "" +msgstr "Запошљавање" #: frontend/src/pages/Home/Home.vue:5 frontend/src/pages/Home/Home.vue:154 msgid "Home" @@ -3062,7 +3062,7 @@ msgstr "Нисам доступан" #: frontend/src/pages/Billing.vue:181 msgid "I consent to my personal information being stored for invoicing" -msgstr "" +msgstr "Слажем се да се моји лични подаци чувају за фактурисање" #: frontend/src/pages/QuizForm.vue:340 msgid "ID" @@ -3900,7 +3900,7 @@ msgstr "Најдужи низ дана" #: frontend/src/components/Modals/EditProfile.vue:95 msgid "Looking for new work or hiring talent?" -msgstr "" +msgstr "Тражите нови посао или запошљавате таленте?" #: lms/templates/emails/payment_reminder.html:23 msgid "Looking forward to seeing you enrolled!" @@ -4065,7 +4065,7 @@ msgstr "Члан" #. Label of the member_consent (Check) field in DocType 'LMS Payment' #: lms/lms/doctype/lms_payment/lms_payment.json msgid "Member Consent" -msgstr "" +msgstr "Сагласност члана" #. Label of the member_count (Int) field in DocType 'LMS Program' #: lms/lms/doctype/lms_program/lms_program.json @@ -4696,7 +4696,7 @@ msgstr "Отвори " #: frontend/src/components/Modals/EditProfile.vue:94 #: lms/fixtures/custom_field.json msgid "Open to" -msgstr "" +msgstr "Отворен за" #: frontend/src/components/UserAvatar.vue:11 #: frontend/src/pages/CertifiedParticipants.vue:46 @@ -5054,7 +5054,7 @@ msgstr "Молимо Вас да се упишете на ову обуку да #: frontend/src/pages/Billing.vue:99 msgid "Please ensure that the billing name you enter is correct, as it will be used on your invoice." -msgstr "" +msgstr "Молимо Вас да проверите да ли је назив за фактурисање које уносите тачно, јер ће бити коришћено на Вашој фактури." #: frontend/src/components/Quiz.vue:16 msgid "Please ensure that you complete all the questions in {0} minutes." @@ -5132,11 +5132,11 @@ msgstr "Молимо Вас да се добро припремите и сти #: frontend/src/pages/Billing.vue:194 msgid "Please provide your consent to proceed with the payment" -msgstr "" +msgstr "Молимо Вас да дате сагласност како бисте наставили са плаћањем" #: frontend/src/pages/Billing.vue:337 msgid "Please provide your consent to proceed with the payment." -msgstr "" +msgstr "Молимо Вас да дате сагласност како бисте наставили са плаћањем." #: frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue:139 msgid "Please run the code to execute the test cases." @@ -5989,7 +5989,7 @@ msgstr "Изаберите квиз" #: frontend/src/components/AssessmentPlugin.vue:41 #: frontend/src/components/AssessmentPlugin.vue:49 msgid "Select an Assignment" -msgstr "" +msgstr "Изаберите задатак" #: frontend/src/components/ContactUsEmail.vue:33 #: frontend/src/pages/JobApplications.vue:115 @@ -7796,7 +7796,7 @@ msgstr "{0} није пронађено" #: frontend/src/pages/Jobs.vue:33 msgid "{0} {1} Jobs" -msgstr "" +msgstr "{0} {1} послова" #. Count format of shortcut in the LMS Workspace #: lms/lms/workspace/lms/lms.json From a03be5ab4dce225d0064cf17008548308a383cf2 Mon Sep 17 00:00:00 2001 From: Jannat Patel <31363128+pateljannat@users.noreply.github.com> Date: Thu, 15 Jan 2026 01:14:14 +0530 Subject: [PATCH 08/21] chore: Serbian (Latin) translations --- lms/locale/sr_CS.po | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lms/locale/sr_CS.po b/lms/locale/sr_CS.po index be704a84..a1be316c 100644 --- a/lms/locale/sr_CS.po +++ b/lms/locale/sr_CS.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: frappe\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n" "POT-Creation-Date: 2026-01-13 05:34+0000\n" -"PO-Revision-Date: 2026-01-13 19:44\n" +"PO-Revision-Date: 2026-01-14 19:44\n" "Last-Translator: jannat@frappe.io\n" "Language-Team: Serbian (Latin)\n" "MIME-Version: 1.0\n" @@ -2412,7 +2412,7 @@ msgstr "Upis u program {0}" #. Label of the enrollment_from_batch (Link) field in DocType 'LMS Enrollment' #: lms/lms/doctype/lms_enrollment/lms_enrollment.json msgid "Enrollment from Batch" -msgstr "" +msgstr "Upis iz grupe" #: lms/lms/doctype/lms_batch_enrollment/lms_batch_enrollment.py:57 msgid "Enrollment in this batch is restricted. Please contact the Administrator." @@ -2730,7 +2730,7 @@ msgstr "Vrsta fajla" #: frontend/src/components/AssessmentPlugin.vue:54 msgid "Filter assignments by course" -msgstr "" +msgstr "Filtriraj zadatke prema obuci" #: frontend/src/components/Settings/Transactions/TransactionList.vue:15 msgid "Filter by Billing Name" @@ -3031,7 +3031,7 @@ msgstr "Istaknuti tekst" #: frontend/src/pages/CertifiedParticipants.vue:52 #: frontend/src/pages/Profile.vue:70 lms/fixtures/custom_field.json msgid "Hiring" -msgstr "" +msgstr "Zapošljavanje" #: frontend/src/pages/Home/Home.vue:5 frontend/src/pages/Home/Home.vue:154 msgid "Home" @@ -3062,7 +3062,7 @@ msgstr "Nisam dostupan" #: frontend/src/pages/Billing.vue:181 msgid "I consent to my personal information being stored for invoicing" -msgstr "" +msgstr "Slažem se da se moji lični podaci čuvaju za fakturisanje" #: frontend/src/pages/QuizForm.vue:340 msgid "ID" @@ -3900,7 +3900,7 @@ msgstr "Najduži niz dana" #: frontend/src/components/Modals/EditProfile.vue:95 msgid "Looking for new work or hiring talent?" -msgstr "" +msgstr "Tražite novi posao ili zapošljavate talente?" #: lms/templates/emails/payment_reminder.html:23 msgid "Looking forward to seeing you enrolled!" @@ -4065,7 +4065,7 @@ msgstr "Član" #. Label of the member_consent (Check) field in DocType 'LMS Payment' #: lms/lms/doctype/lms_payment/lms_payment.json msgid "Member Consent" -msgstr "" +msgstr "Saglasnost člana" #. Label of the member_count (Int) field in DocType 'LMS Program' #: lms/lms/doctype/lms_program/lms_program.json @@ -4696,7 +4696,7 @@ msgstr "Otvori " #: frontend/src/components/Modals/EditProfile.vue:94 #: lms/fixtures/custom_field.json msgid "Open to" -msgstr "" +msgstr "Otvoren za" #: frontend/src/components/UserAvatar.vue:11 #: frontend/src/pages/CertifiedParticipants.vue:46 @@ -5054,7 +5054,7 @@ msgstr "Molimo Vas da se upišete na ovu obuku da biste pristupili lekciji" #: frontend/src/pages/Billing.vue:99 msgid "Please ensure that the billing name you enter is correct, as it will be used on your invoice." -msgstr "" +msgstr "Molimo Vas da proverite da li je naziv za fakturisanje koje unosite tačno, jer će biti korišćeno na Vašoj fakturi." #: frontend/src/components/Quiz.vue:16 msgid "Please ensure that you complete all the questions in {0} minutes." @@ -5132,11 +5132,11 @@ msgstr "Molimo Vas da se dobro pripremite i stignete na vreme za ocenjivanje." #: frontend/src/pages/Billing.vue:194 msgid "Please provide your consent to proceed with the payment" -msgstr "" +msgstr "Molimo Vas da date saglasnost kako biste nastavili sa plaćanjem" #: frontend/src/pages/Billing.vue:337 msgid "Please provide your consent to proceed with the payment." -msgstr "" +msgstr "Molimo Vas da date saglasnost kako biste nastavili sa plaćanjem." #: frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue:139 msgid "Please run the code to execute the test cases." @@ -5989,7 +5989,7 @@ msgstr "Izaberite kviz" #: frontend/src/components/AssessmentPlugin.vue:41 #: frontend/src/components/AssessmentPlugin.vue:49 msgid "Select an Assignment" -msgstr "" +msgstr "Izaberite zadatak" #: frontend/src/components/ContactUsEmail.vue:33 #: frontend/src/pages/JobApplications.vue:115 @@ -7796,7 +7796,7 @@ msgstr "{0} nije pronađeno" #: frontend/src/pages/Jobs.vue:33 msgid "{0} {1} Jobs" -msgstr "" +msgstr "{0} {1} poslova" #. Count format of shortcut in the LMS Workspace #: lms/lms/workspace/lms/lms.json From 078f18d99c02c525468ad40c0555bcf6f643cf31 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Thu, 15 Jan 2026 10:18:09 +0530 Subject: [PATCH 09/21] chore: capture quiz creation and certificate creation for analytics --- frontend/src/pages/BatchForm.vue | 1 - frontend/src/pages/Quizzes.vue | 3 +++ lms/lms/doctype/lms_certificate/lms_certificate.py | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/BatchForm.vue b/frontend/src/pages/BatchForm.vue index 099e9daa..a90223ca 100644 --- a/frontend/src/pages/BatchForm.vue +++ b/frontend/src/pages/BatchForm.vue @@ -464,7 +464,6 @@ const validateFields = () => { !['description', 'batch_details'].includes(key) && typeof batch[key] === 'string' ) { - console.log(key) batch[key] = escapeHTML(batch[key]) } }) diff --git a/frontend/src/pages/Quizzes.vue b/frontend/src/pages/Quizzes.vue index f01742ea..ca0a77fa 100644 --- a/frontend/src/pages/Quizzes.vue +++ b/frontend/src/pages/Quizzes.vue @@ -144,9 +144,11 @@ import { computed, inject, onMounted, ref, watch } from 'vue' import { Plus } from 'lucide-vue-next' import { sessionStore } from '@/stores/session' import { escapeHTML } from '@/utils' +import { useTelemetry } from 'frappe-ui/frappe' import EmptyState from '@/components/EmptyState.vue' const { brand } = sessionStore() +const { capture } = useTelemetry() const user = inject('$user') const dayjs = inject('$dayjs') const router = useRouter() @@ -216,6 +218,7 @@ const insertQuiz = (close) => { toast.success(__('Quiz created successfully')) close() title.value = '' + capture('quiz_created') router.push({ name: 'QuizForm', params: { diff --git a/lms/lms/doctype/lms_certificate/lms_certificate.py b/lms/lms/doctype/lms_certificate/lms_certificate.py index 75c64e6f..ec9f5231 100644 --- a/lms/lms/doctype/lms_certificate/lms_certificate.py +++ b/lms/lms/doctype/lms_certificate/lms_certificate.py @@ -7,6 +7,7 @@ from frappe.email.doctype.email_template.email_template import get_email_templat from frappe.model.document import Document from frappe.model.naming import make_autoname from frappe.utils import nowdate +from frappe.utils.telemetry import capture class LMSCertificate(Document): @@ -17,6 +18,10 @@ class LMSCertificate(Document): self.name = make_autoname("hash", self.doctype) def after_insert(self): + self.send_certification_email() + capture("certificate_issued", "lms") + + def send_certification_email(self): outgoing_email_account = frappe.get_cached_value( "Email Account", {"default_outgoing": 1, "enable_outgoing": 1}, "name" ) From e2c0355821a8302ee24e4ce5560487cbadc56627 Mon Sep 17 00:00:00 2001 From: raizasafeel <89463672+raizasafeel@users.noreply.github.com> Date: Wed, 14 Jan 2026 23:25:11 +0530 Subject: [PATCH 10/21] refactor(batch): simplify dashboard with get_count and conditional rendering --- .../src/components/AdminBatchDashboard.vue | 7 ++++- frontend/src/components/BatchStudents.vue | 9 +++--- lms/lms/utils.py | 28 +++++-------------- 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/frontend/src/components/AdminBatchDashboard.vue b/frontend/src/components/AdminBatchDashboard.vue index 947180c5..135fe84c 100644 --- a/frontend/src/components/AdminBatchDashboard.vue +++ b/frontend/src/components/AdminBatchDashboard.vue @@ -82,18 +82,23 @@ const studentCount = createResource({ const assessmentCount = createResource({ url: 'lms.lms.utils.get_batch_assessment_count', - params: { batch: props.batch?.data?.name }, + cache: ['batch_assessment_count', props.batch?.data?.name], + params: { + batch: props.batch?.data?.name, + }, auto: true, }) const chartData = createResource({ url: 'lms.lms.utils.get_batch_chart_data', + cache: ['batch_chart_data', props.batch?.data?.name], params: { batch: props.batch?.data?.name }, auto: true, }) const certificationCount = createResource({ url: 'frappe.client.get_count', + cache: ['batch_certificate_count', props.batch?.data?.name], params: { doctype: 'LMS Certificate', filters: { batch_name: props.batch?.data?.name }, diff --git a/frontend/src/components/BatchStudents.vue b/frontend/src/components/BatchStudents.vue index 26665db5..1eb56e17 100644 --- a/frontend/src/components/BatchStudents.vue +++ b/frontend/src/components/BatchStudents.vue @@ -88,8 +88,8 @@ -
-
@@ -146,10 +146,11 @@ const props = defineProps({ }) const studentCount = createResource({ - url: 'lms.lms.utils.get_batch_student_count', + url: 'frappe.client.get_count', cache: ['batch_student_count', props.batch?.data?.name], params: { - batch: props.batch?.data?.name, + doctype: 'LMS Batch Enrollment', + filters: { batch: props.batch?.data?.name }, }, auto: true, }) diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 0acb2565..9cd9a516 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -1355,6 +1355,13 @@ def get_exercise_details(assessment, member): assessment.edit_url = f"/exercises/{assessment.assessment_name}/submission/new" +@frappe.whitelist() +def get_batch_assessment_count(batch): + if not frappe.db.exists("LMS Batch", batch): + frappe.throw(_("The specified batch does not exist.")) + return frappe.db.count("LMS Assessment", {"parent": batch}) + + @frappe.whitelist() def get_batch_students(filters, offset=0, limit_start=0, limit_page_length=None, limit=None): # limit_start and limit_page_length are used for backward compatibility @@ -1383,27 +1390,6 @@ def get_batch_students(filters, offset=0, limit_start=0, limit_page_length=None, return students -@frappe.whitelist() -def get_batch_student_count(batch): - if not frappe.db.exists("LMS Batch", batch): - frappe.throw(_("The specified batch does not exist.")) - return frappe.db.count("LMS Batch Enrollment", filters={"batch": batch}) - - -@frappe.whitelist() -def get_batch_certificate_count(batch): - if not frappe.db.exists("LMS Batch", batch): - frappe.throw(_("The specified batch does not exist.")) - return frappe.db.count("LMS Certificate", filters={"batch_name": batch}) - - -@frappe.whitelist() -def get_batch_assessment_count(batch): - if not frappe.db.exists("LMS Batch", batch): - frappe.throw(_("The specified batch does not exist.")) - return frappe.db.count("LMS Assessment", filters={"parent": batch}) - - def get_course_completion_stats(batch): """Get completion counts per course in batch""" BatchCourse = frappe.qb.DocType("Batch Course") From 4a012a99a4ae3e1f17026336c469295f69604cdc Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Thu, 15 Jan 2026 14:47:03 +0530 Subject: [PATCH 11/21] fix: programming exercise test case deletion --- .../src/components/Controls/ChildTable.vue | 94 +++++++++---------- .../ProgrammingExerciseForm.vue | 53 +++++++++-- 2 files changed, 91 insertions(+), 56 deletions(-) diff --git a/frontend/src/components/Controls/ChildTable.vue b/frontend/src/components/Controls/ChildTable.vue index dd34a34f..5e6ef47e 100644 --- a/frontend/src/components/Controls/ChildTable.vue +++ b/frontend/src/components/Controls/ChildTable.vue @@ -3,55 +3,56 @@
{{ label }}
-
-
+
+
- {{ column }} -
-
-
-
- - -
- + {{ column }} +
+
+
+
+ + +
+ -
-
+
@@ -154,10 +155,7 @@ const getGridTemplateColumns = () => { } const toggleMenu = (index: number, event: MouseEvent) => { - const rect = (event.target as HTMLElement).getBoundingClientRect() - menuOpenIndex.value = index - menuTopPosition.value = rect.bottom + 'px' - menuLeftPosition.value = rect.right + 'px' + menuOpenIndex.value = menuOpenIndex.value === index ? null : index } onClickOutside(menuRef, () => { diff --git a/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseForm.vue b/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseForm.vue index 817fdc4a..8ef096fc 100644 --- a/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseForm.vue +++ b/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseForm.vue @@ -1,12 +1,17 @@