diff --git a/frontend/src/components/Controls/Code.vue b/frontend/src/components/Controls/Code.vue index 3440f90e..175bd937 100644 --- a/frontend/src/components/Controls/Code.vue +++ b/frontend/src/components/Controls/Code.vue @@ -107,7 +107,7 @@ async function setLanguageExtension() { if (!languageImport) return const module = await languageImport() - languageExtension.value = (module as any)[props.language]() + languageExtension.value = (module as any)[props.language]?.() if (props.completions) { const languageData = (module as any)[`${props.language}Language`] diff --git a/frontend/src/components/InstallPrompt.vue b/frontend/src/components/InstallPrompt.vue index eea93d0c..ab913feb 100644 --- a/frontend/src/components/InstallPrompt.vue +++ b/frontend/src/components/InstallPrompt.vue @@ -76,7 +76,14 @@ const isIos = () => { const isInStandaloneMode = () => 'standalone' in window.navigator && window.navigator.standalone -if (isIos() && !isInStandaloneMode()) iosInstallMessage.value = true +if ( + isIos() && + !isInStandaloneMode() && + localStorage.getItem('learningIosInstallPromptShown') !== 'true' +) { + iosInstallMessage.value = true + localStorage.setItem('learningIosInstallPromptShown', 'true') +} window.addEventListener('beforeinstallprompt', (e) => { e.preventDefault() diff --git a/frontend/src/components/UpcomingEvaluations.vue b/frontend/src/components/UpcomingEvaluations.vue index 8a64bfc6..edc5551c 100644 --- a/frontend/src/components/UpcomingEvaluations.vue +++ b/frontend/src/components/UpcomingEvaluations.vue @@ -14,7 +14,10 @@
-
+
diff --git a/frontend/src/pages/Home/StudentHome.vue b/frontend/src/pages/Home/StudentHome.vue index 50335af8..babc0dd3 100644 --- a/frontend/src/pages/Home/StudentHome.vue +++ b/frontend/src/pages/Home/StudentHome.vue @@ -64,7 +64,7 @@
-
+
diff --git a/frontend/src/pages/JobApplications.vue b/frontend/src/pages/JobApplications.vue index 92080299..09871823 100644 --- a/frontend/src/pages/JobApplications.vue +++ b/frontend/src/pages/JobApplications.vue @@ -66,38 +66,38 @@ v-if="column.key === 'full_name'" class="flex items-center space-x-3" > - -
- -
- {{ item }} + + {{ item }}
-
-
+
+ {{ item }} +
+
{{ item }}
- +
import { + Avatar, Button, Breadcrumbs, Dialog, @@ -252,6 +253,7 @@ const sendEmail = (close) => { } const downloadResume = (resumeUrl) => { + console.log(resumeUrl) window.open(resumeUrl, '_blank') } @@ -288,7 +290,7 @@ const applicationColumns = computed(() => { }, { label: __('Applied On'), - key: 'applied_date', + key: 'applied_on', width: 1, icon: 'calendar', }, @@ -305,7 +307,7 @@ const applicantRows = computed(() => { return applications.data.map((application) => ({ ...application, full_name: application.full_name, - applied_date: dayjs(application.creation).format('MMM DD, YYYY'), + applied_on: dayjs(application.creation).fromNow(), })) }) diff --git a/frontend/src/pages/Profile.vue b/frontend/src/pages/Profile.vue index 92190a95..f183332a 100644 --- a/frontend/src/pages/Profile.vue +++ b/frontend/src/pages/Profile.vue @@ -190,15 +190,22 @@ const isSessionUser = () => { return $user.data?.email === profile.data?.email } -const hasHigherAccess = () => { +const currentUserHasHigherAccess = () => { return $user.data?.is_evaluator || $user.data?.is_moderator } +const isEvaluatorOrModerator = () => { + return ( + profile.data?.roles?.includes('Batch Evaluator') || + profile.data?.roles?.includes('Moderator') + ) +} + const getTabButtons = () => { let buttons = [{ label: 'About' }, { label: 'Certificates' }] if ($user.data?.is_moderator) buttons.push({ label: 'Roles' }) - if (hasHigherAccess()) { + if (currentUserHasHigherAccess() && isEvaluatorOrModerator()) { buttons.push({ label: 'Slots' }) buttons.push({ label: 'Schedule' }) } diff --git a/frontend/src/pages/ProfileEvaluator.vue b/frontend/src/pages/ProfileEvaluator.vue index 1b8d8d5d..df9af8ba 100644 --- a/frontend/src/pages/ProfileEvaluator.vue +++ b/frontend/src/pages/ProfileEvaluator.vue @@ -176,7 +176,7 @@ const hasHigherAccess = () => { } const isSessionUser = () => { - return user.data?.email === props.profile.data?.email + return user.data?.email === props.profile.data?.name } const showSlotsTemplate = ref(0) diff --git a/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue b/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue index 796c420f..2b75d9c3 100644 --- a/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue +++ b/frontend/src/pages/ProgrammingExercises/ProgrammingExerciseSubmission.vue @@ -266,8 +266,7 @@ const checkIfUserIsPermitted = (doc: any = null) => { !user.data.is_evaluator ) { router.push({ - name: 'ProgrammingExerciseSubmission', - params: { exerciseID: props.exerciseID, submissionID: 'new' }, + name: 'Courses', }) return } diff --git a/lms/lms/api.py b/lms/lms/api.py index 1be4d71e..72861f9c 100644 --- a/lms/lms/api.py +++ b/lms/lms/api.py @@ -1674,9 +1674,12 @@ def get_pwa_manifest(): @frappe.whitelist() def get_profile_details(username): - return frappe.db.get_value( + details = frappe.db.get_value( "User", {"username": username}, ["full_name", "name", "username", "user_image", "bio", "headline", "cover_image"], as_dict=True, ) + + details.roles = frappe.get_roles(details.name) + return details diff --git a/lms/lms/doctype/course_evaluator/course_evaluator.json b/lms/lms/doctype/course_evaluator/course_evaluator.json index 6dc92405..5ffae917 100644 --- a/lms/lms/doctype/course_evaluator/course_evaluator.json +++ b/lms/lms/doctype/course_evaluator/course_evaluator.json @@ -83,8 +83,8 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2025-07-04 12:04:11.007945", - "modified_by": "Administrator", + "modified": "2025-11-10 11:41:51.802016", + "modified_by": "sayali@frappe.io", "module": "LMS", "name": "Course Evaluator", "naming_rule": "By fieldname", @@ -131,5 +131,6 @@ "sort_field": "modified", "sort_order": "DESC", "states": [], - "title_field": "full_name" + "title_field": "full_name", + "track_changes": 1 } diff --git a/lms/lms/doctype/lms_assignment/lms_assignment.json b/lms/lms/doctype/lms_assignment/lms_assignment.json index dcd21f23..20851dc7 100644 --- a/lms/lms/doctype/lms_assignment/lms_assignment.json +++ b/lms/lms/doctype/lms_assignment/lms_assignment.json @@ -70,10 +70,11 @@ "fieldtype": "Section Break" } ], + "grid_page_length": 50, "index_web_pages_for_search": 1, "links": [], - "modified": "2024-12-24 09:36:31.464508", - "modified_by": "Administrator", + "modified": "2025-11-10 11:40:38.157448", + "modified_by": "sayali@frappe.io", "module": "LMS", "name": "LMS Assignment", "naming_rule": "Expression (old style)", @@ -113,9 +114,11 @@ "share": 1 } ], + "row_format": "Dynamic", "show_title_field_in_link": 1, "sort_field": "modified", "sort_order": "DESC", "states": [], - "title_field": "title" -} \ No newline at end of file + "title_field": "title", + "track_changes": 1 +} diff --git a/lms/lms/doctype/lms_badge_assignment/lms_badge_assignment.json b/lms/lms/doctype/lms_badge_assignment/lms_badge_assignment.json index 9c804933..a7f7d241 100644 --- a/lms/lms/doctype/lms_badge_assignment/lms_badge_assignment.json +++ b/lms/lms/doctype/lms_badge_assignment/lms_badge_assignment.json @@ -84,7 +84,7 @@ "grid_page_length": 50, "index_web_pages_for_search": 1, "links": [], - "modified": "2025-11-06 11:38:35.903520", + "modified": "2025-11-10 11:39:42.233779", "modified_by": "sayali@frappe.io", "module": "LMS", "name": "LMS Badge Assignment", @@ -166,5 +166,6 @@ "sort_field": "creation", "sort_order": "DESC", "states": [], - "title_field": "member" + "title_field": "member", + "track_changes": 1 } diff --git a/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.json b/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.json index b834a5a7..b57020ba 100644 --- a/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.json +++ b/lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.json @@ -131,10 +131,11 @@ "read_only": 1 } ], + "grid_page_length": 50, "index_web_pages_for_search": 1, "links": [], - "modified": "2024-09-11 11:20:06.233491", - "modified_by": "Administrator", + "modified": "2025-11-10 11:41:38.999620", + "modified_by": "sayali@frappe.io", "module": "LMS", "name": "LMS Certificate Evaluation", "owner": "Administrator", @@ -164,6 +165,7 @@ "write": 1 } ], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "DESC", "states": [ @@ -184,5 +186,6 @@ "title": "In Progress" } ], - "title_field": "member_name" -} \ No newline at end of file + "title_field": "member_name", + "track_changes": 1 +} diff --git a/lms/lms/doctype/lms_certificate_request/lms_certificate_request.json b/lms/lms/doctype/lms_certificate_request/lms_certificate_request.json index 311d8d8b..61aa15f2 100644 --- a/lms/lms/doctype/lms_certificate_request/lms_certificate_request.json +++ b/lms/lms/doctype/lms_certificate_request/lms_certificate_request.json @@ -157,7 +157,7 @@ "grid_page_length": 50, "index_web_pages_for_search": 1, "links": [], - "modified": "2025-10-13 14:30:57.897102", + "modified": "2025-11-10 11:40:50.679211", "modified_by": "sayali@frappe.io", "module": "LMS", "name": "LMS Certificate Request", @@ -228,5 +228,6 @@ "title": "Cancelled" } ], - "title_field": "member_name" + "title_field": "member_name", + "track_changes": 1 } diff --git a/lms/lms/doctype/lms_question/lms_question.json b/lms/lms/doctype/lms_question/lms_question.json index 50d19627..971d56d1 100644 --- a/lms/lms/doctype/lms_question/lms_question.json +++ b/lms/lms/doctype/lms_question/lms_question.json @@ -193,11 +193,12 @@ "label": "Possible Answer 4" } ], + "grid_page_length": 50, "index_web_pages_for_search": 1, "links": [], "make_attachments_public": 1, - "modified": "2024-10-07 09:41:17.862774", - "modified_by": "Administrator", + "modified": "2025-11-10 11:40:18.568547", + "modified_by": "sayali@frappe.io", "module": "LMS", "name": "LMS Question", "naming_rule": "Expression", @@ -240,8 +241,10 @@ "write": 1 } ], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "DESC", "states": [], - "title_field": "question" -} \ No newline at end of file + "title_field": "question", + "track_changes": 1 +} diff --git a/lms/lms/doctype/lms_source/lms_source.json b/lms/lms/doctype/lms_source/lms_source.json index a1361696..ea75d118 100644 --- a/lms/lms/doctype/lms_source/lms_source.json +++ b/lms/lms/doctype/lms_source/lms_source.json @@ -18,10 +18,11 @@ "unique": 1 } ], + "grid_page_length": 50, "index_web_pages_for_search": 1, "links": [], - "modified": "2023-10-26 17:25:09.144367", - "modified_by": "Administrator", + "modified": "2025-11-10 11:39:57.251861", + "modified_by": "sayali@frappe.io", "module": "LMS", "name": "LMS Source", "naming_rule": "By fieldname", @@ -62,8 +63,10 @@ "share": 1 } ], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "DESC", "states": [], - "title_field": "source" -} \ No newline at end of file + "title_field": "source", + "track_changes": 1 +} diff --git a/lms/lms/doctype/lms_zoom_settings/lms_zoom_settings.json b/lms/lms/doctype/lms_zoom_settings/lms_zoom_settings.json index 656ed144..53dbf8eb 100644 --- a/lms/lms/doctype/lms_zoom_settings/lms_zoom_settings.json +++ b/lms/lms/doctype/lms_zoom_settings/lms_zoom_settings.json @@ -83,7 +83,7 @@ "grid_page_length": 50, "index_web_pages_for_search": 1, "links": [], - "modified": "2025-07-08 12:20:48.314056", + "modified": "2025-11-10 11:39:13.146961", "modified_by": "sayali@frappe.io", "module": "LMS", "name": "LMS Zoom Settings", @@ -131,5 +131,6 @@ "row_format": "Dynamic", "sort_field": "creation", "sort_order": "DESC", - "states": [] + "states": [], + "track_changes": 1 }