diff --git a/frontend/src/components/Sidebar/AppSidebar.vue b/frontend/src/components/Sidebar/AppSidebar.vue
index b51e72a5..cdc8c94e 100644
--- a/frontend/src/components/Sidebar/AppSidebar.vue
+++ b/frontend/src/components/Sidebar/AppSidebar.vue
@@ -9,11 +9,21 @@
>
-
-
+
+
+ {{ __(link.label) }}
+
+
{
- addNotifications()
- setSidebarLinks()
setUpOnboarding()
addKeyboardShortcut()
socket.on('publish_lms_notifications', (data) => {
@@ -278,9 +281,14 @@ const setSidebarLinks = () => {
onSuccess(data) {
Object.keys(data).forEach((key) => {
if (!parseInt(data[key])) {
- sidebarLinks.value = sidebarLinks.value.filter(
+ sidebarLinks.value.forEach((link) => {
+ link.items = link.items.filter(
+ (item) => item.label.toLowerCase().split(' ').join('_') !== key
+ )
+ })
+ /* sidebarLinks.value = sidebarLinks.value?.items.filter(
(link) => link.label.toLowerCase().split(' ').join('_') !== key
- )
+ ) */
}
})
},
@@ -319,85 +327,16 @@ const unreadNotifications = createResource({
},
onSuccess(data) {
unreadCount.value = data
- sidebarLinks.value = sidebarLinks.value.map((link) => {
+ /* sidebarLinks.value = sidebarLinks.value.map((link) => {
if (link.label === 'Notifications') {
link.count = data
}
return link
- })
+ }) */
},
auto: user ? true : false,
})
-const addNotifications = () => {
- if (user) {
- sidebarLinks.value.push({
- label: 'Notifications',
- icon: 'Bell',
- to: 'Notifications',
- activeFor: ['Notifications'],
- count: unreadCount.value,
- })
- }
-}
-
-const addQuizzes = () => {
- if (!isInstructor.value && !isModerator.value) return
-
- const quizzesLinkExists = sidebarLinks.value.some(
- (link) => link.label === 'Quizzes'
- )
- if (quizzesLinkExists) return
-
- sidebarLinks.value.splice(4, 0, {
- label: 'Quizzes',
- icon: 'CircleHelp',
- to: 'Quizzes',
- activeFor: ['Quizzes', 'QuizForm', 'QuizSubmissionList', 'QuizSubmission'],
- })
-}
-
-const addAssignments = () => {
- if (!isInstructor.value && !isModerator.value) return
-
- const assignmentsLinkExists = sidebarLinks.value.some(
- (link) => link.label === 'Assignments'
- )
- if (assignmentsLinkExists) return
-
- sidebarLinks.value.splice(5, 0, {
- label: 'Assignments',
- icon: 'Pencil',
- to: 'Assignments',
- activeFor: [
- 'Assignments',
- 'AssignmentForm',
- 'AssignmentSubmissionList',
- 'AssignmentSubmission',
- ],
- })
-}
-
-const addProgrammingExercises = () => {
- if (!isInstructor.value && !isModerator.value) return
- const programmingExercisesLinkExists = sidebarLinks.value.some(
- (link) => link.label === 'Programming Exercises'
- )
- if (programmingExercisesLinkExists) return
-
- sidebarLinks.value.splice(3, 0, {
- label: 'Programming Exercises',
- icon: 'Code',
- to: 'ProgrammingExercises',
- activeFor: [
- 'ProgrammingExercises',
- 'ProgrammingExerciseForm',
- 'ProgrammingExerciseSubmissions',
- 'ProgrammingExerciseSubmission',
- ],
- })
-}
-
const addPrograms = async () => {
const programsLinkExists = sidebarLinks.value.some(
(link) => link.label === 'Programs'
@@ -417,45 +356,6 @@ const addPrograms = async () => {
})
}
-const addContactUsDetails = () => {
- if (!settings?.data?.contact_us_email && !settings?.data?.contact_us_url)
- return
-
- const contactUsLinkExists = sidebarLinks.value.some(
- (link) => link.label === 'Contact Us'
- )
- if (contactUsLinkExists) return
-
- sidebarLinks.value.push({
- label: 'Contact Us',
- icon: settings.data?.contact_us_url ? 'Headset' : 'Mail',
- to: settings.data?.contact_us_url
- ? settings.data?.contact_us_url
- : settings.data?.contact_us_email,
- })
-}
-
-const checkIfCanAddProgram = async () => {
- if (isModerator.value || isInstructor.value) {
- return true
- }
- const programs = await call('lms.lms.utils.get_programs')
- return programs.enrolled.length > 0 || programs.published.length > 0
-}
-
-const addHome = () => {
- const homeLinkExists = sidebarLinks.value.some(
- (link) => link.label === 'Home'
- )
- if (homeLinkExists) return
- sidebarLinks.value.unshift({
- label: 'Home',
- icon: 'Home',
- to: 'Home',
- activeFor: ['Home'],
- })
-}
-
const openPageModal = (link) => {
showPageModal.value = true
pageToEdit.value = link
@@ -700,16 +600,15 @@ const setUpOnboarding = () => {
}
}
-watch(userResource, () => {
- addContactUsDetails()
+watch(userResource, async () => {
+ await userResource.promise
+ sidebarLinks.value = getSidebarLinks()
+ setSidebarLinks()
if (userResource.data) {
isModerator.value = userResource.data.is_moderator
isInstructor.value = userResource.data.is_instructor
- addHome()
- addPrograms()
- addProgrammingExercises()
- addQuizzes()
- addAssignments()
+ await programs.promise
+ sidebarLinks.value = getSidebarLinks()
setUpOnboarding()
}
})
diff --git a/frontend/src/stores/settings.js b/frontend/src/stores/settings.js
index f1689f0d..b0cf32f0 100644
--- a/frontend/src/stores/settings.js
+++ b/frontend/src/stores/settings.js
@@ -1,7 +1,6 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { createResource } from 'frappe-ui'
-import { sessionStore } from './session'
export const useSettings = defineStore('settings', () => {
const isSettingsOpen = ref(false)
@@ -20,10 +19,16 @@ export const useSettings = defineStore('settings', () => {
auto: false,
})
+ const programs = createResource({
+ url: 'lms.lms.utils.get_programs',
+ auto: false,
+ })
+
return {
+ activeTab,
isSettingsOpen,
isCommandPaletteOpen,
- activeTab,
+ programs,
settings,
sidebarSettings,
}
diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js
index 6b46946c..d18bc98a 100644
--- a/frontend/src/utils/index.js
+++ b/frontend/src/utils/index.js
@@ -403,51 +403,177 @@ export function getUserTimezone() {
}
export function getSidebarLinks() {
+ let links = getSidebarItems()
+
+ links.forEach((link) => {
+ link.items = link.items.filter((item) => {
+ return item.condition ? item.condition() : true
+ })
+ })
+
+ links = links.filter((link) => {
+ return link.items.length > 0
+ })
+
+ return links
+}
+
+const getSidebarItems = () => {
+ const { userResource } = usersStore()
+ const { settings } = useSettings()
+
return [
{
- label: 'Search',
- icon: 'Search',
- to: 'Search',
- },
- {
- label: 'Courses',
- icon: 'BookOpen',
- to: 'Courses',
- activeFor: [
- 'Courses',
- 'CourseDetail',
- 'Lesson',
- 'CourseForm',
- 'LessonForm',
+ label: 'General',
+ hideLabel: true,
+ items: [
+ {
+ label: 'Home',
+ icon: 'Home',
+ to: 'Home',
+ condition: () => {
+ return userResource?.data
+ },
+ },
+ {
+ label: 'Search',
+ icon: 'Search',
+ to: 'Search',
+ condition: () => {
+ return userResource?.data
+ },
+ },
+ {
+ label: 'Notifications',
+ icon: 'Bell',
+ to: 'Notifications',
+ condition: () => {
+ return userResource?.data
+ },
+ },
],
},
{
- label: 'Batches',
- icon: 'Users',
- to: 'Batches',
- activeFor: ['Batches', 'BatchDetail', 'Batch', 'BatchForm'],
+ label: 'Learning',
+ hideLabel: true,
+ items: [
+ {
+ label: 'Courses',
+ icon: 'BookOpen',
+ to: 'Courses',
+ activeFor: [
+ 'Courses',
+ 'CourseDetail',
+ 'Lesson',
+ 'CourseForm',
+ 'LessonForm',
+ ],
+ },
+ {
+ label: 'Programs',
+ icon: 'Route',
+ to: 'Programs',
+ activeFor: ['Programs', 'ProgramDetail'],
+ await: true,
+ condition: () => {
+ return checkIfCanAddProgram()
+ },
+ },
+ {
+ label: 'Batches',
+ icon: 'Users',
+ to: 'Batches',
+ activeFor: ['Batches', 'BatchDetail', 'Batch', 'BatchForm'],
+ },
+ {
+ label: 'Certifications',
+ icon: 'GraduationCap',
+ to: 'CertifiedParticipants',
+ activeFor: ['CertifiedParticipants'],
+ },
+ {
+ label: 'Jobs',
+ icon: 'Briefcase',
+ to: 'Jobs',
+ activeFor: ['Jobs', 'JobDetail'],
+ },
+ {
+ label: 'Statistics',
+ icon: 'TrendingUp',
+ to: 'Statistics',
+ activeFor: ['Statistics'],
+ },
+ {
+ label: 'Contact Us',
+ icon: settings.data?.contact_us_url ? 'Headset' : 'Mail',
+ to: settings.data?.contact_us_url
+ ? settings.data?.contact_us_url
+ : settings.data?.contact_us_email,
+ condition: () => {
+ return (
+ settings?.data?.contact_us_email ||
+ settings?.data?.contact_us_url
+ )
+ },
+ },
+ ],
},
{
- label: 'Certifications',
- icon: 'GraduationCap',
- to: 'CertifiedParticipants',
- activeFor: ['CertifiedParticipants'],
- },
- {
- label: 'Jobs',
- icon: 'Briefcase',
- to: 'Jobs',
- activeFor: ['Jobs', 'JobDetail'],
- },
- {
- label: 'Statistics',
- icon: 'TrendingUp',
- to: 'Statistics',
- activeFor: ['Statistics'],
+ label: 'Assessments',
+ hideLabel: true,
+ items: [
+ {
+ label: 'Quizzes',
+ icon: 'CircleHelp',
+ to: 'Quizzes',
+ condition: () => {
+ return isAdmin()
+ },
+ },
+ {
+ label: 'Assignments',
+ icon: 'Pencil',
+ to: 'Assignments',
+ condition: () => {
+ return isAdmin()
+ },
+ },
+ {
+ label: 'Programming Exercises',
+ icon: 'Code',
+ to: 'ProgrammingExercises',
+ condition: () => {
+ return isAdmin()
+ },
+ },
+ ],
},
]
}
+const isAdmin = () => {
+ const { userResource } = usersStore()
+ return (
+ userResource?.data?.is_instructor ||
+ userResource?.data?.is_moderator ||
+ userResource.data?.is_evaluator
+ )
+}
+
+const checkIfCanAddProgram = () => {
+ const { userResource } = usersStore()
+ const { programs } = useSettings()
+ if (!userResource.data) return false
+ if (userResource?.data?.is_moderator || userResource?.data?.is_instructor) {
+ return true
+ }
+ console.log('programs.data', programs.data)
+ return (
+ programs.data?.enrolled.length > 0 ||
+ programs.data?.published.length > 0
+ )
+}
+
export function getFormattedDateRange(
startDate,
endDate,
diff --git a/lms/lms/doctype/lms_course/lms_course.json b/lms/lms/doctype/lms_course/lms_course.json
index b30ed240..f4b03ffa 100644
--- a/lms/lms/doctype/lms_course/lms_course.json
+++ b/lms/lms/doctype/lms_course/lms_course.json
@@ -313,7 +313,7 @@
}
],
"make_attachments_public": 1,
- "modified": "2025-11-25 11:35:17.924569",
+ "modified": "2025-12-11 17:21:05.231761",
"modified_by": "sayali@frappe.io",
"module": "LMS",
"name": "LMS Course",
@@ -336,6 +336,7 @@
"delete": 1,
"email": 1,
"export": 1,
+ "import": 1,
"print": 1,
"read": 1,
"report": 1,
@@ -348,6 +349,7 @@
"delete": 1,
"email": 1,
"export": 1,
+ "import": 1,
"print": 1,
"read": 1,
"report": 1,