Compare commits

...

30 Commits

Author SHA1 Message Date
Frappe PR Bot
1ecdbd9e06 chore(release): Bumped to Version 2.13.0 2024-11-25 09:21:10 +00:00
Jannat Patel
a90e3d611c Merge pull request #1150 from pateljannat/roles-desk-access-issue
fix: desk access and course amount validation issue
2024-11-25 14:49:28 +05:30
Jannat Patel
d49d638253 fix: amount validation for course 2024-11-25 14:36:32 +05:30
Jannat Patel
83338a56c0 fix: disable desk_access for lms roles 2024-11-25 14:26:11 +05:30
Jannat Patel
562020de70 Merge pull request #1149 from frappe/l10n_develop2
chore: sync translations from crowdin
2024-11-25 11:00:48 +05:30
Jannat Patel
044907edeb Merge pull request #1148 from frappe/pot_develop_2024-11-22
chore: update POT file
2024-11-25 11:00:32 +05:30
Jannat Patel
cfa1aa87fc Merge pull request #1115 from yarin-zhang/develop
Add Chinese locale
2024-11-25 11:00:17 +05:30
Jannat Patel
0ac32ee474 chore: Swedish translations 2024-11-25 00:49:11 +05:30
Jannat Patel
de0675f850 chore: Persian translations 2024-11-23 23:46:59 +05:30
frappe-pr-bot
1c529790f2 chore: update POT file 2024-11-22 16:05:29 +00:00
Jannat Patel
40bcc4d572 Merge pull request #1147 from pateljannat/onboarding-steps
feat: onboarding steps
2024-11-22 16:47:12 +05:30
Jannat Patel
58f109e79c feat: onboarding steps 2024-11-22 16:28:28 +05:30
沨沄极客
cb324f6269 Merge branch 'develop' into develop 2024-11-22 15:29:15 +08:00
Jannat Patel
7cafaf5cbc Merge pull request #1145 from pateljannat/learning-paths
feat: learning paths
2024-11-22 11:12:42 +05:30
Jannat Patel
a394952630 Merge pull request #1146 from frappe/l10n_develop2
chore: sync translations from crowdin
2024-11-22 11:07:41 +05:30
Jannat Patel
68e87f20aa feat: added progress column in program members list 2024-11-22 11:07:23 +05:30
Jannat Patel
64ed0b3e94 feat: program restrictions 2024-11-21 17:10:24 +05:30
Jannat Patel
fcaaee958d chore: Persian translations 2024-11-20 23:08:25 +05:30
Jannat Patel
29e356ff86 Merge pull request #1144 from pateljannat/issues-52
fix: changed SCORM input from checkbox to switch with better description
2024-11-20 20:20:41 +05:30
Jannat Patel
460edc7bc7 fix: changed SCORM input from checkbox to switch with better description 2024-11-20 19:52:28 +05:30
Jannat Patel
582c7af12d feat: reorder courses and students view for programs 2024-11-20 19:32:49 +05:30
Jannat Patel
e1a78382c3 feat: learning paths 2024-11-18 16:15:27 +05:30
沨沄极客
4ee1693434 Merge branch 'develop' into develop 2024-11-17 17:37:33 +08:00
yarin-zhang
1ba63a2175 Update Chinese locale 2024-11-14 16:58:04 +08:00
沨沄极客
b5551fd8ba Merge branch 'develop' into develop 2024-11-14 16:56:30 +08:00
yarin-zhang
fac0038af8 Update Chinese locale 2024-11-14 16:52:52 +08:00
yarin-zhang
ee6685e324 Update Chinese locale 2024-11-14 16:38:54 +08:00
yarin-zhang
0fb18f995c Update Chinese locale 2024-11-14 16:19:14 +08:00
yarin-zhang
5e6160149f Update Revision Date 2024-11-11 11:13:26 +08:00
yarin-zhang
be66c563a8 Add Chinese locale 2024-11-11 10:30:34 +08:00
43 changed files with 2416 additions and 963 deletions

View File

@@ -99,6 +99,7 @@ import { getSidebarLinks } from '../utils'
import { usersStore } from '@/stores/user' import { usersStore } from '@/stores/user'
import { sessionStore } from '@/stores/session' import { sessionStore } from '@/stores/session'
import { useSidebar } from '@/stores/sidebar' import { useSidebar } from '@/stores/sidebar'
import { useSettings } from '@/stores/settings'
import { ChevronRight, Plus } from 'lucide-vue-next' import { ChevronRight, Plus } from 'lucide-vue-next'
import { createResource, Button } from 'frappe-ui' import { createResource, Button } from 'frappe-ui'
import PageModal from '@/components/Modals/PageModal.vue' import PageModal from '@/components/Modals/PageModal.vue'
@@ -114,6 +115,7 @@ const isModerator = ref(false)
const isInstructor = ref(false) const isInstructor = ref(false)
const pageToEdit = ref(null) const pageToEdit = ref(null)
const showWebPages = ref(false) const showWebPages = ref(false)
const settingsStore = useSettings()
onMounted(() => { onMounted(() => {
socket.on('publish_lms_notifications', (data) => { socket.on('publish_lms_notifications', (data) => {
@@ -183,6 +185,28 @@ const addQuizzes = () => {
} }
} }
const addPrograms = () => {
if (settingsStore.learningPaths.data) {
let activeFor = ['Programs', 'ProgramForm']
let index = 1
if (!isInstructor.value && !isModerator.value) {
sidebarLinks.value = sidebarLinks.value.filter(
(link) => link.label !== 'Courses'
)
activeFor.push('CourseDetail')
activeFor.push('Lesson')
index = 0
}
sidebarLinks.value.splice(index, 0, {
label: 'Programs',
icon: 'Route',
to: 'Programs',
activeFor: activeFor,
})
}
}
const openPageModal = (link) => { const openPageModal = (link) => {
showPageModal.value = true showPageModal.value = true
pageToEdit.value = link pageToEdit.value = link
@@ -215,6 +239,7 @@ watch(userResource, () => {
isModerator.value = userResource.data.is_moderator isModerator.value = userResource.data.is_moderator
isInstructor.value = userResource.data.is_instructor isInstructor.value = userResource.data.is_instructor
addQuizzes() addQuizzes()
addPrograms()
} }
}) })

View File

@@ -92,7 +92,7 @@
{{ option.label }} {{ option.label }}
</div> </div>
<div <div
v-if="option.label != option.description" v-if="option.description"
class="text-xs text-gray-700" class="text-xs text-gray-700"
v-html="option.description" v-html="option.description"
></div> ></div>

View File

@@ -44,6 +44,7 @@
</div> </div>
</template> </template>
</Autocomplete> </Autocomplete>
<p v-if="description" class="text-sm text-gray-600">{{ description }}</p>
</div> </div>
</template> </template>
@@ -67,6 +68,10 @@ const props = defineProps({
type: String, type: String,
default: '', default: '',
}, },
description: {
type: String,
default: '',
},
}) })
const emit = defineEmits(['update:modelValue', 'change']) const emit = defineEmits(['update:modelValue', 'change'])
@@ -118,7 +123,7 @@ const options = createResource({
transform: (data) => { transform: (data) => {
return data.map((option) => { return data.map((option) => {
return { return {
label: option.value, label: option.label || option.value,
value: option.value, value: option.value,
description: option.description, description: option.description,
} }

View File

@@ -303,9 +303,9 @@ const trashChapter = (chapterName) => {
} }
const redirectToChapter = (chapter) => { const redirectToChapter = (chapter) => {
if (!chapter.is_scorm_package) return
event.preventDefault() event.preventDefault()
if (props.allowEdit) return if (props.allowEdit) return
if (!chapter.is_scorm_package) return
if (!user.data) { if (!user.data) {
showToast( showToast(
__('You are not enrolled'), __('You are not enrolled'),

View File

@@ -8,6 +8,7 @@
<AppSidebar /> <AppSidebar />
</div> </div>
<div class="w-full overflow-auto" id="scrollContainer"> <div class="w-full overflow-auto" id="scrollContainer">
<OnboardingBanner />
<slot /> <slot />
</div> </div>
</div> </div>
@@ -16,4 +17,5 @@
</template> </template>
<script setup> <script setup>
import AppSidebar from './AppSidebar.vue' import AppSidebar from './AppSidebar.vue'
import OnboardingBanner from '@/components/OnboardingBanner.vue'
</script> </script>

View File

@@ -17,10 +17,15 @@
<template #body-content> <template #body-content>
<div class="space-y-4 text-base"> <div class="space-y-4 text-base">
<FormControl label="Title" v-model="chapter.title" :required="true" /> <FormControl label="Title" v-model="chapter.title" :required="true" />
<FormControl <Switch
:label="__('Is SCORM Package')" size="sm"
:label="__('SCORM Package')"
:description="
__(
'Enable this only if you want to upload a SCORM package as a chapter.'
)
"
v-model="chapter.is_scorm_package" v-model="chapter.is_scorm_package"
type="checkbox"
/> />
<div v-if="chapter.is_scorm_package"> <div v-if="chapter.is_scorm_package">
<FileUploader <FileUploader
@@ -70,14 +75,17 @@ import {
Dialog, Dialog,
FileUploader, FileUploader,
FormControl, FormControl,
Switch,
} from 'frappe-ui' } from 'frappe-ui'
import { defineModel, reactive, watch, ref } from 'vue' import { defineModel, reactive, watch } from 'vue'
import { showToast, getFileSize } from '@/utils/' import { showToast, getFileSize } from '@/utils/'
import { capture } from '@/telemetry' import { capture } from '@/telemetry'
import { FileText, X } from 'lucide-vue-next' import { FileText, X } from 'lucide-vue-next'
import { useSettings } from '@/stores/settings'
const show = defineModel() const show = defineModel()
const outline = defineModel('outline') const outline = defineModel('outline')
const settingsStore = useSettings()
const props = defineProps({ const props = defineProps({
course: { course: {
@@ -137,6 +145,9 @@ const addChapter = async (close) => {
{ {
onSuccess(data) { onSuccess(data) {
cleanChapter() cleanChapter()
if (!settingsStore.onboardingDetails.data?.is_onboarded) {
settingsStore.onboardingDetails.reload()
}
outline.value.reload() outline.value.reload()
showToast( showToast(
__('Success'), __('Success'),

View File

@@ -108,9 +108,31 @@ const tabsStructure = computed(() => {
hideLabel: true, hideLabel: true,
items: [ items: [
{ {
label: 'Members', label: 'General',
description: 'Manage the members of your learning system', icon: 'Wrench',
icon: 'UserRoundPlus', fields: [
{
label: 'Enable Learning Paths',
name: 'enable_learning_paths',
description:
'This will enforce students to go through programs assigned to them in the correct order.',
type: 'checkbox',
},
{
label: 'Send calendar invite for evaluations',
name: 'send_calendar_invite_for_evaluations',
description:
'If enabled, it sends google calendar invite to the student for evaluations.',
type: 'checkbox',
},
{
label: 'Unsplash Access Key',
name: 'unsplash_access_key',
description:
'Optional. If this is set, students can pick a cover image from the unsplash library for their profile page. https://unsplash.com/documentation#getting-started.',
type: 'text',
},
],
}, },
], ],
}, },
@@ -156,9 +178,14 @@ const tabsStructure = computed(() => {
], ],
}, },
{ {
label: 'Settings', label: 'Lists',
hideLabel: true, hideLabel: false,
items: [ items: [
{
label: 'Members',
description: 'Manage the members of your learning system',
icon: 'UserRoundPlus',
},
{ {
label: 'Categories', label: 'Categories',
description: 'Manage the members of your learning system', description: 'Manage the members of your learning system',

View File

@@ -0,0 +1,151 @@
<template>
<div v-if="showOnboardingBanner && onboardingDetails.data">
<Tooltip :text="__('Skip Onboarding')" placement="left">
<X
class="w-4 h-4 stroke-1 absolute top-2 right-2 cursor-pointer mr-1"
@click="skipOnboarding.reload()"
/>
</Tooltip>
<div class="flex items-center justify-evenly bg-gray-100 p-10">
<div
@click="redirectToCourseForm()"
class="flex items-center space-x-2"
:class="{
'cursor-pointer': !onboardingDetails.data.course_created.length,
}"
>
<span
v-if="onboardingDetails.data.course_created.length"
class="py-1 px-1 bg-white rounded-full"
>
<Check class="h-4 w-4 stroke-2 text-green-600" />
</span>
<span v-else class="font-semibold bg-white px-2 py-1 rounded-full">
1
</span>
<span class="text-lg font-semibold">
{{ __('Create a course') }}
</span>
</div>
<div
@click="redirectToChapterForm()"
class="flex items-center space-x-2"
:class="{
'cursor-pointer':
onboardingDetails.data.course_created.length &&
!onboardingDetails.data.chapter_created.length,
'text-gray-400': !onboardingDetails.data.course_created.length,
}"
>
<span
v-if="onboardingDetails.data.chapter_created.length"
class="py-1 px-1 bg-white rounded-full"
>
<Check class="h-4 w-4 stroke-2 text-green-600" />
</span>
<span v-else class="font-semibold bg-white px-2 py-1 rounded-full">
2
</span>
<span class="text-lg font-semibold">
{{ __('Add a chapter') }}
</span>
</div>
<div
@click="redirectToLessonForm()"
class="flex items-center space-x-2"
:class="{
'cursor-pointer':
onboardingDetails.data.course_created.length &&
onboardingDetails.data.chapter_created.length,
'text-gray-400':
!onboardingDetails.data.course_created.length ||
!onboardingDetails.data.chapter_created.length,
}"
>
<span
v-if="onboardingDetails.data.lesson_created.length"
class="py-1 px-1 bg-white rounded-full"
>
<Check class="h-4 w-4 stroke-2 text-green-600" />
</span>
<span class="font-semibold bg-white px-2 py-1 rounded-full"> 3 </span>
<span class="text-lg font-semibold">
{{ __('Add a lesson') }}
</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { Check, X } from 'lucide-vue-next'
import { useRouter } from 'vue-router'
import { useSettings } from '@/stores/settings'
import { createResource, Tooltip } from 'frappe-ui'
const showOnboardingBanner = ref(false)
const settings = useSettings()
const onboardingDetails = settings.onboardingDetails
const router = useRouter()
watch(onboardingDetails, () => {
if (!onboardingDetails.data?.is_onboarded) {
showOnboardingBanner.value = true
} else {
showOnboardingBanner.value = false
}
})
const redirectToCourseForm = () => {
if (onboardingDetails.data?.course_created.length) {
return
} else {
router.push({ name: 'CourseForm', params: { courseName: 'new' } })
}
}
const redirectToChapterForm = () => {
if (!onboardingDetails.data?.course_created.length) {
return
} else {
router.push({
name: 'CourseForm',
params: {
courseName: onboardingDetails.data?.first_course,
},
})
}
}
const redirectToLessonForm = () => {
if (!onboardingDetails.data?.course_created.length) {
return
} else if (!onboardingDetails.data?.chapter_created.length) {
return
} else {
router.push({
name: 'LessonForm',
params: {
courseName: onboardingDetails.data?.first_course,
chapterNumber: 1,
lessonNumber: 1,
},
})
}
}
const skipOnboarding = createResource({
url: 'frappe.client.set_value',
makeParams() {
return {
doctype: 'LMS Settings',
name: 'LMS Settings',
fieldname: 'is_onboarding_complete',
value: 1,
}
},
onSuccess(data) {
onboardingDetails.reload()
},
})
</script>

View File

@@ -397,6 +397,9 @@ const attempts = createResource({
watch( watch(
() => quiz.data, () => quiz.data,
() => { () => {
if (quiz.data) {
populateQuestions()
}
if (quiz.data && quiz.data.max_attempts) { if (quiz.data && quiz.data.max_attempts) {
attempts.reload() attempts.reload()
resetQuiz() resetQuiz()

View File

@@ -29,6 +29,7 @@
<script setup> <script setup>
import { Button, Badge } from 'frappe-ui' import { Button, Badge } from 'frappe-ui'
import SettingFields from '@/components/SettingFields.vue' import SettingFields from '@/components/SettingFields.vue'
import { showToast } from '@/utils'
const props = defineProps({ const props = defineProps({
fields: { fields: {
@@ -54,7 +55,14 @@ const update = () => {
props.data.doc[f.name] = f.value props.data.doc[f.name] = f.value
} }
}) })
props.data.save.submit() props.data.save.submit(
{},
{
onError(err) {
showToast('Error', err.messages?.[0] || err, 'x')
},
}
)
} }
</script> </script>

View File

@@ -90,6 +90,7 @@
:type="field.type" :type="field.type"
:rows="field.rows" :rows="field.rows"
:options="field.options" :options="field.options"
:description="field.description"
/> />
</div> </div>
</div> </div>
@@ -100,7 +101,7 @@
import { FormControl, FileUploader, Button, Switch } from 'frappe-ui' import { FormControl, FileUploader, Button, Switch } from 'frappe-ui'
import { computed } from 'vue' import { computed } from 'vue'
import { getFileSize, validateFile } from '@/utils' import { getFileSize, validateFile } from '@/utils'
import { X, FileText } from 'lucide-vue-next' import { X } from 'lucide-vue-next'
import Link from '@/components/Controls/Link.vue' import Link from '@/components/Controls/Link.vue'
import CodeEditor from '@/components/Controls/CodeEditor.vue' import CodeEditor from '@/components/Controls/CodeEditor.vue'

View File

@@ -434,6 +434,9 @@ const submitCourse = () => {
onSuccess(data) { onSuccess(data) {
capture('course_created') capture('course_created')
showToast('Success', 'Course created successfully', 'check') showToast('Success', 'Course created successfully', 'check')
if (!settingsStore.onboardingDetails.data?.is_onboarded) {
settingsStore.onboardingDetails.reload()
}
router.push({ router.push({
name: 'CourseForm', name: 'CourseForm',
params: { courseName: data.name }, params: { courseName: data.name },

View File

@@ -160,30 +160,45 @@
<script setup> <script setup>
import { import {
Breadcrumbs,
Tabs,
Badge, Badge,
Breadcrumbs,
Button, Button,
FormControl, call,
createResource, createResource,
FormControl,
Tabs,
} from 'frappe-ui' } from 'frappe-ui'
import CourseCard from '@/components/CourseCard.vue' import CourseCard from '@/components/CourseCard.vue'
import { BookOpen, Plus, Search } from 'lucide-vue-next' import { BookOpen, Plus, Search } from 'lucide-vue-next'
import { ref, computed, inject, onMounted, watch } from 'vue' import { ref, computed, inject, onMounted, watch } from 'vue'
import { updateDocumentTitle } from '@/utils' import { updateDocumentTitle } from '@/utils'
import { useRouter } from 'vue-router'
import { useSettings } from '@/stores/settings'
const user = inject('$user') const user = inject('$user')
const searchQuery = ref('') const searchQuery = ref('')
const currentCategory = ref(null) const currentCategory = ref(null)
const hasCourses = ref(false) const hasCourses = ref(false)
const router = useRouter()
const settings = useSettings()
onMounted(() => { onMounted(() => {
checkLearningPath()
let queries = new URLSearchParams(location.search) let queries = new URLSearchParams(location.search)
if (queries.has('category')) { if (queries.has('category')) {
currentCategory.value = queries.get('category') currentCategory.value = queries.get('category')
} }
}) })
const checkLearningPath = () => {
if (
settings.learningPaths.data &&
(!user.data?.is_moderator || !user.data?.is_instructor)
) {
router.push({ name: 'Programs' })
}
}
const courses = createResource({ const courses = createResource({
url: 'lms.lms.utils.get_courses', url: 'lms.lms.utils.get_courses',
cache: ['courses', user.data?.email], cache: ['courses', user.data?.email],

View File

@@ -92,11 +92,13 @@ import LessonHelp from '@/components/LessonHelp.vue'
import { ChevronRight } from 'lucide-vue-next' import { ChevronRight } from 'lucide-vue-next'
import { updateDocumentTitle, createToast, getEditorTools } from '@/utils' import { updateDocumentTitle, createToast, getEditorTools } from '@/utils'
import { capture } from '@/telemetry' import { capture } from '@/telemetry'
import { useSettings } from '@/stores/settings'
const editor = ref(null) const editor = ref(null)
const instructorEditor = ref(null) const instructorEditor = ref(null)
const user = inject('$user') const user = inject('$user')
const openInstructorEditor = ref(false) const openInstructorEditor = ref(false)
const settingsStore = useSettings()
let autoSaveInterval let autoSaveInterval
let showSuccessMessage = false let showSuccessMessage = false
@@ -393,6 +395,9 @@ const createNewLesson = () => {
onSuccess() { onSuccess() {
capture('lesson_created') capture('lesson_created')
showToast('Success', 'Lesson created successfully', 'check') showToast('Success', 'Lesson created successfully', 'check')
if (!settingsStore.onboardingDetails.data?.is_onboarded) {
settingsStore.onboardingDetails.reload()
}
lessonDetails.reload() lessonDetails.reload()
}, },
} }

View File

@@ -0,0 +1,354 @@
<template>
<header
class="sticky top-0 z-10 flex flex-col md:flex-row md:items-center justify-between border-b bg-white px-3 py-2.5 sm:px-5"
>
<Breadcrumbs :items="breadbrumbs" />
<Button variant="solid">
{{ __('Save') }}
</Button>
</header>
<div v-if="program.doc" class="pt-5 px-5 w-3/4 mx-auto space-y-10">
<FormControl v-model="program.doc.title" :label="__('Title')" />
<!-- Courses -->
<div>
<div class="flex items-center justify-between mb-2">
<div class="text-lg font-semibold">
{{ __('Program Courses') }}
</div>
<Button
@click="
() => {
currentForm = 'course'
showDialog = true
}
"
>
<template #prefix>
<Plus class="w-4 h-4" />
</template>
{{ __('Add') }}
</Button>
</div>
<ListView
:columns="courseColumns"
:rows="program.doc.program_courses"
row-key="name"
:options="{
showTooltip: false,
}"
>
<ListHeader
class="mb-2 grid items-center space-x-4 rounded bg-gray-100 p-2"
>
<ListHeaderItem :item="item" v-for="item in courseColumns" />
</ListHeader>
<ListRows>
<Draggable
:list="program.doc.program_courses"
item-key="name"
group="items"
@end="updateOrder"
>
<template #item="{ element: row }">
<ListRow :row="row" />
</template>
</Draggable>
</ListRows>
<ListSelectBanner>
<template #actions="{ unselectAll, selections }">
<div class="flex gap-2">
<Button
variant="ghost"
@click="remove(selections, unselectAll, 'program_courses')"
>
<Trash2 class="h-4 w-4 stroke-1.5" />
</Button>
</div>
</template>
</ListSelectBanner>
</ListView>
</div>
<!-- Members -->
<div>
<div class="flex items-center justify-between mb-2">
<div class="text-lg font-semibold">
{{ __('Program Members') }}
</div>
<Button
@click="
() => {
currentForm = 'member'
showDialog = true
}
"
>
<template #prefix>
<Plus class="w-4 h-4" />
</template>
{{ __('Add') }}
</Button>
</div>
<ListView
:columns="memberColumns"
:rows="program.doc.program_members"
row-key="name"
:options="{
showTooltip: false,
}"
>
<ListHeader
class="mb-2 grid items-center space-x-4 rounded bg-gray-100 p-2"
>
<ListHeaderItem :item="item" v-for="item in memberColumns" />
</ListHeader>
<ListRows>
<ListRow :row="row" v-for="row in program.doc.program_members" />
</ListRows>
<ListSelectBanner>
<template #actions="{ unselectAll, selections }">
<div class="flex gap-2">
<Button
variant="ghost"
@click="remove(selections, unselectAll, 'program_members')"
>
<Trash2 class="h-4 w-4 stroke-1.5" />
</Button>
</div>
</template>
</ListSelectBanner>
</ListView>
</div>
</div>
<Dialog
v-model="showDialog"
:options="{
title:
currentForm == 'course'
? __('New Program Course')
: __('New Program Member'),
actions: [
{
label: __('Add'),
variant: 'solid',
onClick: () =>
currentForm == 'course'
? addProgramCourse(close)
: addProgramMember(close),
},
],
}"
>
<template #body-content>
<Link
v-if="currentForm == 'course'"
v-model="course"
doctype="LMS Course"
:filters="{
disable_self_learning: 1,
}"
:label="__('Program Course')"
:description="
__(
'Only courses for which self learning is disabled can be added to program.'
)
"
/>
<Link
v-if="currentForm == 'member'"
v-model="member"
doctype="User"
:filters="{
ignore_user_type: 1,
}"
:label="__('Program Member')"
/>
</template>
</Dialog>
</template>
<script setup>
import {
Breadcrumbs,
Button,
call,
createDocumentResource,
Dialog,
FormControl,
ListView,
ListRows,
ListRow,
ListHeader,
ListHeaderItem,
ListSelectBanner,
} from 'frappe-ui'
import { computed, ref } from 'vue'
import { Plus, Trash2 } from 'lucide-vue-next'
import Link from '@/components/Controls/Link.vue'
import { showToast } from '@/utils/'
import Draggable from 'vuedraggable'
const showDialog = ref(false)
const currentForm = ref(null)
const course = ref(null)
const member = ref(null)
const props = defineProps({
programName: {
type: String,
required: true,
},
})
const program = createDocumentResource({
doctype: 'LMS Program',
name: props.programName,
auto: true,
cache: ['program', props.programName],
})
const addProgramCourse = () => {
program.setValue.submit(
{
program_courses: [
...program.doc.program_courses,
{ course: course.value },
],
},
{
onSuccess(data) {
showDialog.value = false
course.value = null
showToast(__('Success'), __('Course added to program'), 'check')
program.reload()
},
onError(err) {
showToast('Error', err.messages?.[0] || err, 'x')
},
}
)
}
const addProgramMember = () => {
program.setValue.submit(
{
program_members: [
...program.doc.program_members,
{ member: member.value },
],
},
{
onSuccess(data) {
showDialog.value = false
member.value = null
showToast(__('Success'), __('Member added to program'), 'check')
program.reload()
},
onError(err) {
showToast('Error', err.messages?.[0] || err, 'x')
},
}
)
}
const remove = (selections, unselectAll, doctype) => {
selections = Array.from(selections)
program.setValue.submit(
{
[doctype]: program.doc[doctype].filter(
(row) => !selections.includes(row.name)
),
},
{
onSuccess(data) {
unselectAll()
showToast(__('Success'), __('Items removed successfully'), 'check')
program.reload()
},
onError(err) {
showToast('Error', err.messages?.[0] || err, 'x')
},
}
)
}
const updateOrder = (e) => {
let sourceIdx = e.from.dataset.idx
let targetIdx = e.to.dataset.idx
let courses = program.doc.program_courses
courses.splice(targetIdx, 0, courses.splice(sourceIdx, 1)[0])
courses.forEach((course, index) => {
course.idx = index + 1
})
program.setValue.submit(
{
program_courses: courses,
},
{
onSuccess(data) {
showToast(__('Success'), __('Course moved successfully'), 'check')
program.reload()
},
onError(err) {
showToast('Error', err.messages?.[0] || err, 'x')
},
}
)
}
const courseColumns = computed(() => {
return [
{
label: 'Title',
key: 'course_title',
width: 3,
},
{
label: 'ID',
key: 'course',
width: 3,
},
]
})
const memberColumns = computed(() => {
return [
{
label: 'Member',
key: 'member',
width: 3,
align: 'left',
},
{
label: 'Full Name',
key: 'full_name',
width: 3,
align: 'left',
},
{
label: 'Progress',
key: 'progress',
width: 3,
align: 'left',
},
]
})
const breadbrumbs = computed(() => {
return [
{
label: 'Programs',
route: { name: 'Programs' },
},
{
label: props.programName === 'new' ? 'New Program' : props.programName,
},
]
})
</script>

View File

@@ -0,0 +1,185 @@
<template>
<header
class="sticky top-0 z-10 flex items-center justify-between border-b bg-white px-3 py-2.5 sm:px-5"
>
<Breadcrumbs :items="breadbrumbs" />
<Button
v-if="user.data?.is_moderator || user.data?.is_instructor"
@click="showDialog = true"
variant="solid"
>
<template #prefix>
<Plus class="h-4 w-4 stroke-1.5" />
</template>
{{ __('New') }}
</Button>
</header>
<div v-if="programs.data?.length" class="pt-5 px-5">
<div v-for="program in programs.data" class="mb-20">
<div class="flex items-center justify-between">
<div class="text-xl font-semibold">
{{ program.name }}
</div>
<div class="flex items-center space-x-2">
<Badge
v-if="program.members"
variant="subtle"
theme="green"
size="lg"
>
{{ program.members }}
{{
program.members == 1 ? __(singularize('members')) : __('members')
}}
</Badge>
<Badge
v-if="program.progress"
variant="subtle"
theme="blue"
size="lg"
>
{{ program.progress }}{{ __('% completed') }}
</Badge>
<router-link
v-if="user.data?.is_moderator || user.data?.is_instructor"
:to="{
name: 'ProgramForm',
params: { programName: program.name },
}"
>
<Button>
<template #prefix>
<Edit class="h-4 w-4 stroke-1.5" />
</template>
{{ __('Edit') }}
</Button>
</router-link>
</div>
</div>
<div
v-if="program.courses?.length"
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 mt-5"
>
<CourseCard
v-for="course in program.courses"
:course="course"
@click="enrollMember(program.name, course.name)"
class="cursor-pointer"
/>
</div>
<div v-else class="text-sm italic text-gray-600 mt-4">
{{ __('No courses in this program') }}
</div>
</div>
</div>
<div
v-else
class="text-center p-5 text-gray-600 mt-52 w-3/4 md:w-1/2 mx-auto space-y-2"
>
<BookOpen class="size-10 mx-auto stroke-1 text-gray-500" />
<div class="text-xl font-medium">
{{ __('No programs found') }}
</div>
<div class="leading-5">
{{
__(
'There are no programs available at the moment. Keep an eye out, fresh learning experiences are on the way soon!'
)
}}
</div>
</div>
<Dialog
v-model="showDialog"
:options="{
title: __('New Program'),
actions: [
{
label: __('Create'),
variant: 'solid',
onClick: () => createProgram(close),
},
],
}"
>
<template #body-content>
<FormControl :label="__('Title')" v-model="title" />
</template>
</Dialog>
</template>
<script setup>
import {
Badge,
Breadcrumbs,
Button,
call,
createResource,
Dialog,
FormControl,
} from 'frappe-ui'
import { computed, inject, ref } from 'vue'
import { BookOpen, Edit, Plus } from 'lucide-vue-next'
import CourseCard from '@/components/CourseCard.vue'
import { useRouter } from 'vue-router'
import { showToast, singularize } from '@/utils'
const user = inject('$user')
const showDialog = ref(false)
const router = useRouter()
const title = ref('')
const programs = createResource({
url: 'lms.lms.utils.get_programs',
auto: true,
cache: 'programs',
})
const createProgram = (close) => {
call('frappe.client.insert', {
doc: {
doctype: 'LMS Program',
title: title.value,
},
}).then((res) => {
router.push({ name: 'ProgramForm', params: { programName: res.name } })
})
}
const enrollMember = (program, course) => {
call('lms.lms.utils.enroll_in_program_course', {
program: program,
course: course,
})
.then((data) => {
if (data.current_lesson) {
router.push({
name: 'Lesson',
params: {
courseName: course,
chapterNumber: data.current_lesson.split('-')[0],
lessonNumber: data.current_lesson.split('-')[1],
},
})
} else if (data) {
router.push({
name: 'Lesson',
params: {
courseName: course,
chapterNumber: 1,
lessonNumber: 1,
},
})
}
})
.catch((err) => {
showToast('Error', err.messages?.[0] || err, 'x')
})
}
const breadbrumbs = computed(() => [
{
label: 'Programs',
},
])
</script>

View File

@@ -182,6 +182,17 @@ const routes = [
component: () => import('@/pages/QuizSubmission.vue'), component: () => import('@/pages/QuizSubmission.vue'),
props: true, props: true,
}, },
{
path: '/programs/:programName',
name: 'ProgramForm',
component: () => import('@/pages/ProgramForm.vue'),
props: true,
},
{
path: '/programs',
name: 'Programs',
component: () => import('@/pages/Programs.vue'),
},
] ]
let router = createRouter({ let router = createRouter({

View File

@@ -1,12 +1,32 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ref } from 'vue' import { ref } from 'vue'
import { createResource } from 'frappe-ui'
export const useSettings = defineStore('settings', () => { export const useSettings = defineStore('settings', () => {
const isSettingsOpen = ref(false) const isSettingsOpen = ref(false)
const activeTab = ref(null) const activeTab = ref(null)
const learningPaths = createResource({
url: 'frappe.client.get_single_value',
makeParams(values) {
return {
doctype: 'LMS Settings',
field: 'enable_learning_paths',
}
},
auto: true,
cache: ['learningPaths'],
})
const onboardingDetails = createResource({
url: 'lms.lms.utils.is_onboarding_complete',
auto: true,
cache: ['onboardingDetails'],
})
return { return {
isSettingsOpen, isSettingsOpen,
activeTab, activeTab,
learningPaths,
onboardingDetails,
} }
}) })

View File

@@ -1 +1 @@
__version__ = "2.12.0" __version__ = "2.13.0"

View File

@@ -66,7 +66,9 @@ def delete_lms_roles():
def create_course_creator_role(): def create_course_creator_role():
if not frappe.db.exists("Role", "Course Creator"): if frappe.db.exists("Role", "Course Creator"):
frappe.db.set_value("Role", "Course Creator", "desk_access", 0)
else:
role = frappe.get_doc( role = frappe.get_doc(
{ {
"doctype": "Role", "doctype": "Role",
@@ -79,7 +81,9 @@ def create_course_creator_role():
def create_moderator_role(): def create_moderator_role():
if not frappe.db.exists("Role", "Moderator"): if frappe.db.exists("Role", "Moderator"):
frappe.db.set_value("Role", "Moderator", "desk_access", 0)
else:
role = frappe.get_doc( role = frappe.get_doc(
{ {
"doctype": "Role", "doctype": "Role",
@@ -92,7 +96,9 @@ def create_moderator_role():
def create_evaluator_role(): def create_evaluator_role():
if not frappe.db.exists("Role", "Batch Evaluator"): if frappe.db.exists("Role", "Batch Evaluator"):
frappe.db.set_value("Role", "Batch Evaluator", "desk_access", 0)
else:
role = frappe.new_doc("Role") role = frappe.new_doc("Role")
role.update( role.update(
{ {
@@ -105,7 +111,9 @@ def create_evaluator_role():
def create_lms_student_role(): def create_lms_student_role():
if not frappe.db.exists("Role", "LMS Student"): if frappe.db.exists("Role", "LMS Student"):
frappe.db.set_value("Role", "LMS Student", "desk_access", 0)
else:
role = frappe.new_doc("Role") role = frappe.new_doc("Role")
role.update( role.update(
{ {

View File

@@ -93,15 +93,15 @@ def save_progress(lesson, course):
frappe.db.set_value("LMS Enrollment", membership, "current_lesson", lesson) frappe.db.set_value("LMS Enrollment", membership, "current_lesson", lesson)
quiz_completed = get_quiz_progress(lesson)
if not quiz_completed:
return 0
if frappe.db.exists( if frappe.db.exists(
"LMS Course Progress", {"lesson": lesson, "member": frappe.session.user} "LMS Course Progress", {"lesson": lesson, "member": frappe.session.user}
): ):
return return
quiz_completed = get_quiz_progress(lesson)
if not quiz_completed:
return 0
frappe.get_doc( frappe.get_doc(
{ {
"doctype": "LMS Course Progress", "doctype": "LMS Course Progress",

View File

@@ -53,7 +53,7 @@ class LMSCourse(Document):
frappe.throw(_("Please install the Payments app to create a paid courses.")) frappe.throw(_("Please install the Payments app to create a paid courses."))
def validate_amount_and_currency(self): def validate_amount_and_currency(self):
if self.paid_course and (not self.amount and not self.currency): if self.paid_course and (not self.course_price and not self.currency):
frappe.throw(_("Amount and currency are required for paid courses.")) frappe.throw(_("Amount and currency are required for paid courses."))
def on_update(self): def on_update(self):

View File

@@ -4,6 +4,7 @@
import frappe import frappe
from frappe import _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from frappe.utils import ceil
class LMSEnrollment(Document): class LMSEnrollment(Document):
@@ -11,6 +12,9 @@ class LMSEnrollment(Document):
self.validate_membership_in_same_batch() self.validate_membership_in_same_batch()
self.validate_membership_in_different_batch_same_course() self.validate_membership_in_different_batch_same_course()
def on_update(self):
self.update_program_progress()
def validate_membership_in_same_batch(self): def validate_membership_in_same_batch(self):
filters = {"member": self.member, "course": self.course, "name": ["!=", self.name]} filters = {"member": self.member, "course": self.course, "name": ["!=", self.name]}
if self.batch_old: if self.batch_old:
@@ -55,6 +59,26 @@ class LMSEnrollment(Document):
) )
) )
def update_program_progress(self):
programs = frappe.get_all(
"LMS Program Member", {"member": self.member}, ["parent", "name"]
)
for program in programs:
total_progress = 0
courses = frappe.get_all(
"LMS Program Course", {"parent": program.parent}, pluck="course"
)
for course in courses:
progress = frappe.db.get_value(
"LMS Enrollment", {"course": course, "member": self.member}, "progress"
)
progress = progress or 0
total_progress += progress
average_progress = ceil(total_progress / len(courses))
frappe.db.set_value("LMS Program Member", program.name, "progress", average_progress)
@frappe.whitelist() @frappe.whitelist()
def create_membership( def create_membership(

View File

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2024, Frappe and contributors
// For license information, please see license.txt
// frappe.ui.form.on("LMS Program", {
// refresh(frm) {
// },
// });

View File

@@ -0,0 +1,84 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "field:title",
"creation": "2024-11-18 12:27:13.283169",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"title",
"program_courses",
"program_members"
],
"fields": [
{
"fieldname": "program_courses",
"fieldtype": "Table",
"label": "Program Courses",
"options": "LMS Program Course"
},
{
"fieldname": "program_members",
"fieldtype": "Table",
"label": "Program Members",
"options": "LMS Program Member"
},
{
"fieldname": "title",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Title",
"reqd": 1,
"unique": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-11-20 12:26:02.214628",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Program",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Moderator",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Course Creator",
"share": 1,
"write": 1
}
],
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,32 @@
# Copyright (c) 2024, Frappe and contributors
# For license information, please see license.txt
import frappe
from frappe import _
from frappe.model.document import Document
class LMSProgram(Document):
def validate(self):
self.validate_program_courses()
self.validate_program_members()
def validate_program_courses(self):
courses = [row.course for row in self.program_courses]
duplicates = {course for course in courses if courses.count(course) > 1}
if len(duplicates):
frappe.throw(
_("Course {0} has already been added to this batch.").format(
frappe.bold(next(iter(duplicates)))
)
)
def validate_program_members(self):
members = [row.member for row in self.program_members]
duplicates = {member for member in members if members.count(member) > 1}
if len(duplicates):
frappe.throw(
_("Member {0} has already been added to this batch.").format(
frappe.bold(next(iter(duplicates)))
)
)

View File

@@ -0,0 +1,21 @@
# Copyright (c) 2024, Frappe and Contributors
# See license.txt
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record depdendencies are recursively loaded
# Use these module variables to add/remove to/from that list
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class TestLMSProgram(UnitTestCase):
"""
Unit tests for LMSProgram.
Use this class for testing individual functions and methods.
"""
pass

View File

@@ -0,0 +1,42 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2024-11-18 12:27:37.030302",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"course",
"course_title"
],
"fields": [
{
"fieldname": "course",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Course",
"options": "LMS Course",
"reqd": 1
},
{
"fetch_from": "course.title",
"fieldname": "course_title",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Course Title",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-11-18 12:43:46.800199",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Program Course",
"owner": "Administrator",
"permissions": [],
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2024, Frappe and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class LMSProgramCourse(Document):
pass

View File

@@ -0,0 +1,50 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2024-11-18 12:29:13.615014",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"member",
"full_name",
"progress"
],
"fields": [
{
"fieldname": "member",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Member",
"options": "User",
"reqd": 1
},
{
"fetch_from": "member.full_name",
"fieldname": "full_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Full Name",
"read_only": 1
},
{
"default": "0",
"fieldname": "progress",
"fieldtype": "Int",
"in_list_view": 1,
"label": "Progress"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-11-21 12:51:31.882576",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Program Member",
"owner": "Administrator",
"permissions": [],
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2024, Frappe and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class LMSProgramMember(Document):
pass

View File

@@ -5,13 +5,15 @@
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
"general_tab",
"default_home", "default_home",
"send_calendar_invite_for_evaluations",
"is_onboarding_complete", "is_onboarding_complete",
"column_break_zdel", "column_break_zdel",
"enable_learning_paths",
"unsplash_access_key", "unsplash_access_key",
"livecode_url", "livecode_url",
"section_break_szgq", "section_break_szgq",
"send_calendar_invite_for_evaluations",
"show_day_view", "show_day_view",
"column_break_2", "column_break_2",
"show_dashboard", "show_dashboard",
@@ -80,6 +82,7 @@
{ {
"fieldname": "mentor_request_section", "fieldname": "mentor_request_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 1,
"label": "Mentor Request" "label": "Mentor Request"
}, },
{ {
@@ -127,6 +130,7 @@
{ {
"fieldname": "section_break_szgq", "fieldname": "section_break_szgq",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 1,
"label": "Batch Settings" "label": "Batch Settings"
}, },
{ {
@@ -336,12 +340,23 @@
"fieldname": "payments_app_is_not_installed", "fieldname": "payments_app_is_not_installed",
"fieldtype": "HTML", "fieldtype": "HTML",
"label": "Payments app is not installed" "label": "Payments app is not installed"
},
{
"default": "0",
"fieldname": "enable_learning_paths",
"fieldtype": "Check",
"label": "Enable Learning Paths"
},
{
"fieldname": "general_tab",
"fieldtype": "Tab Break",
"label": "General"
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2024-10-01 12:15:49.800242", "modified": "2024-11-20 11:55:05.358421",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "LMS Settings", "name": "LMS Settings",
@@ -356,6 +371,13 @@
"role": "System Manager", "role": "System Manager",
"share": 1, "share": 1,
"write": 1 "write": 1
},
{
"email": 1,
"print": 1,
"read": 1,
"role": "LMS Student",
"share": 1
} }
], ],
"sort_field": "modified", "sort_field": "modified",

View File

@@ -855,7 +855,10 @@ def get_telemetry_boot_info():
} }
@frappe.whitelist()
def is_onboarding_complete(): def is_onboarding_complete():
if not has_course_moderator_role():
return {"is_onboarded": False}
course_created = frappe.db.a_row_exists("LMS Course") course_created = frappe.db.a_row_exists("LMS Course")
chapter_created = frappe.db.a_row_exists("Course Chapter") chapter_created = frappe.db.a_row_exists("Course Chapter")
lesson_created = frappe.db.a_row_exists("Course Lesson") lesson_created = frappe.db.a_row_exists("Course Lesson")
@@ -1751,3 +1754,81 @@ def enroll_in_batch(batch, payment_name=None):
) )
student.save(ignore_permissions=True) student.save(ignore_permissions=True)
@frappe.whitelist()
def get_programs():
if (
has_course_moderator_role()
or has_course_instructor_role()
or has_course_evaluator_role()
):
programs = frappe.get_all("LMS Program", fields=["name"])
else:
programs = frappe.get_all(
"LMS Program Member", {"member": frappe.session.user}, ["parent as name", "progress"]
)
for program in programs:
program_courses = frappe.get_all(
"LMS Program Course", {"parent": program.name}, ["course"], order_by="idx"
)
program.courses = []
for course in program_courses:
program.courses.append(get_course_details(course.course))
program.members = frappe.db.count("LMS Program Member", {"parent": program.name})
return programs
@frappe.whitelist()
def enroll_in_program_course(program, course):
enrollment = frappe.db.exists(
"LMS Enrollment", {"member": frappe.session.user, "course": course}
)
if enrollment:
enrollment = frappe.db.get_value(
"LMS Enrollment", enrollment, ["name", "current_lesson"], as_dict=1
)
enrollment.current_lesson = get_lesson_index(enrollment.current_lesson)
return enrollment
program_courses = frappe.get_all(
"LMS Program Course", {"parent": program}, ["course", "idx"], order_by="idx"
)
current_course_idx = [
program_course.idx
for program_course in program_courses
if program_course.course == course
][0]
for program_course in program_courses:
if program_course.idx < current_course_idx:
enrollment = frappe.db.get_value(
"LMS Enrollment",
{"member": frappe.session.user, "course": program_course.course},
["name", "progress"],
as_dict=1,
)
if enrollment and enrollment.progress != 100:
frappe.throw(
_("Please complete the previous courses in the program to enroll in this course.")
)
elif not enrollment:
frappe.throw(
_("Please complete the previous courses in the program to enroll in this course.")
)
else:
continue
enrollment = frappe.new_doc("LMS Enrollment")
enrollment.update(
{
"member": frappe.session.user,
"course": course,
}
)
enrollment.save()
return enrollment

View File

@@ -1,4 +1,5 @@
{ {
"app": "lms",
"charts": [ "charts": [
{ {
"chart_name": "New Signups", "chart_name": "New Signups",
@@ -145,7 +146,7 @@
"type": "Link" "type": "Link"
} }
], ],
"modified": "2024-08-09 13:19:06.273056", "modified": "2024-11-21 12:16:25.886431",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "LMS", "name": "LMS",
@@ -212,5 +213,6 @@
"type": "DocType" "type": "DocType"
} }
], ],
"title": "LMS" "title": "LMS",
} "type": "Workspace"
}

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n" "Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: jannat@frappe.io\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n"
"POT-Creation-Date: 2024-11-15 16:04+0000\n" "POT-Creation-Date: 2024-11-15 16:04+0000\n"
"PO-Revision-Date: 2024-11-18 17:32\n" "PO-Revision-Date: 2024-11-23 18:16\n"
"Last-Translator: jannat@frappe.io\n" "Last-Translator: jannat@frappe.io\n"
"Language-Team: Persian\n" "Language-Team: Persian\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@@ -183,7 +183,7 @@ msgstr "آدرس خط 2"
#: lms/lms/doctype/cohort_web_page/cohort_web_page.json #: lms/lms/doctype/cohort_web_page/cohort_web_page.json
#: lms/lms/doctype/lms_enrollment/lms_enrollment.json #: lms/lms/doctype/lms_enrollment/lms_enrollment.json
msgid "Admin" msgid "Admin"
msgstr "اَدمین" msgstr "ادمین"
#. Name of a role #. Name of a role
#: lms/lms/doctype/lms_badge/lms_badge.json #: lms/lms/doctype/lms_badge/lms_badge.json
@@ -729,11 +729,11 @@ msgstr ""
#: frontend/src/components/Modals/ChapterModal.vue:149 #: frontend/src/components/Modals/ChapterModal.vue:149
msgid "Chapter added successfully" msgid "Chapter added successfully"
msgstr "" msgstr "فصل با موفقیت اضافه شد"
#: frontend/src/components/Modals/ChapterModal.vue:193 #: frontend/src/components/Modals/ChapterModal.vue:193
msgid "Chapter updated successfully" msgid "Chapter updated successfully"
msgstr "" msgstr "فصل با موفقیت به روز شد"
#. Label of the chapters (Table) field in DocType 'LMS Course' #. Label of the chapters (Table) field in DocType 'LMS Course'
#. Group in LMS Course's connections #. Group in LMS Course's connections
@@ -1157,7 +1157,7 @@ msgstr "اسم دوره"
#: frontend/src/pages/CourseDetail.vue:74 #: frontend/src/pages/CourseDetail.vue:74
msgid "Course Outline" msgid "Course Outline"
msgstr "" msgstr "طرح کلی دوره"
#. Label of the course_price (Currency) field in DocType 'LMS Course' #. Label of the course_price (Currency) field in DocType 'LMS Course'
#: frontend/src/pages/CourseForm.vue:219 #: frontend/src/pages/CourseForm.vue:219
@@ -1197,7 +1197,7 @@ msgstr "دوره قبلاً به دسته اضافه شده است."
#: frontend/src/pages/CourseForm.vue:457 #: frontend/src/pages/CourseForm.vue:457
msgid "Course deleted successfully" msgid "Course deleted successfully"
msgstr "" msgstr "دوره با موفقیت حذف شد"
#: lms/lms/doctype/lms_batch/lms_batch.py:58 #: lms/lms/doctype/lms_batch/lms_batch.py:58
msgid "Course {0} has already been added to this batch." msgid "Course {0} has already been added to this batch."
@@ -1366,19 +1366,19 @@ msgstr "حذف"
#: frontend/src/components/CourseOutline.vue:52 #: frontend/src/components/CourseOutline.vue:52
msgid "Delete Chapter" msgid "Delete Chapter"
msgstr "" msgstr "حذف فصل"
#: frontend/src/pages/CourseForm.vue:464 #: frontend/src/pages/CourseForm.vue:464
msgid "Delete Course" msgid "Delete Course"
msgstr "" msgstr "حذف دوره"
#: frontend/src/components/CourseOutline.vue:287 #: frontend/src/components/CourseOutline.vue:287
msgid "Delete this chapter?" msgid "Delete this chapter?"
msgstr "" msgstr "این فصل حذف شود؟"
#: frontend/src/components/CourseOutline.vue:229 #: frontend/src/components/CourseOutline.vue:229
msgid "Delete this lesson?" msgid "Delete this lesson?"
msgstr "" msgstr "این درس حذف شود؟"
#: frontend/src/pages/CourseForm.vue:465 #: frontend/src/pages/CourseForm.vue:465
msgid "Deleting the course will also delete all its chapters and lessons. Are you sure you want to delete this course?" msgid "Deleting the course will also delete all its chapters and lessons. Are you sure you want to delete this course?"
@@ -1386,11 +1386,11 @@ msgstr ""
#: frontend/src/components/CourseOutline.vue:288 #: frontend/src/components/CourseOutline.vue:288
msgid "Deleting this chapter will also delete all its lessons and permanently remove it from the course. This action cannot be undone. Are you sure you want to continue?" msgid "Deleting this chapter will also delete all its lessons and permanently remove it from the course. This action cannot be undone. Are you sure you want to continue?"
msgstr "" msgstr "با حذف این فصل، تمام دروس آن نیز حذف می شود و برای همیشه از دوره حذف می شود. این عمل قابل بازگشت نیست. آیا مطمئن هستید که می خواهید ادامه دهید؟"
#: frontend/src/components/CourseOutline.vue:230 #: frontend/src/components/CourseOutline.vue:230
msgid "Deleting this lesson will permanently remove it from the course. This action cannot be undone. Are you sure you want to continue?" msgid "Deleting this lesson will permanently remove it from the course. This action cannot be undone. Are you sure you want to continue?"
msgstr "" msgstr "حذف این درس آن را برای همیشه از دوره حذف می کند. این عمل قابل بازگشت نیست. آیا مطمئن هستید که می خواهید ادامه دهید؟"
#. Label of the description (Text Editor) field in DocType 'Job Opportunity' #. Label of the description (Text Editor) field in DocType 'Job Opportunity'
#. Label of the description (Small Text) field in DocType 'Certification' #. Label of the description (Small Text) field in DocType 'Certification'
@@ -1763,7 +1763,7 @@ msgstr "رویداد"
#: frontend/src/pages/BatchForm.vue:156 #: frontend/src/pages/BatchForm.vue:156
msgid "Example: IST (+5:30)" msgid "Example: IST (+5:30)"
msgstr "" msgstr "مثال: IST (+5:30)"
#. Label of the exercise (Link) field in DocType 'Exercise Latest Submission' #. Label of the exercise (Link) field in DocType 'Exercise Latest Submission'
#. Label of the exercise (Link) field in DocType 'Exercise Submission' #. Label of the exercise (Link) field in DocType 'Exercise Submission'
@@ -3287,7 +3287,7 @@ msgstr ""
#: frontend/src/components/Modals/ChapterModal.vue:223 #: frontend/src/components/Modals/ChapterModal.vue:223
msgid "Only zip files are allowed" msgid "Only zip files are allowed"
msgstr "" msgstr "فقط فایل های zip مجاز هستند"
#. Option for the 'Status' (Select) field in DocType 'Job Opportunity' #. Option for the 'Status' (Select) field in DocType 'Job Opportunity'
#. Option for the 'Membership' (Select) field in DocType 'LMS Batch Old' #. Option for the 'Membership' (Select) field in DocType 'LMS Batch Old'
@@ -3551,7 +3551,7 @@ msgstr ""
#: lms/overrides/user.py:240 #: lms/overrides/user.py:240
msgid "Please ask your administrator to verify your sign-up" msgid "Please ask your administrator to verify your sign-up"
msgstr "لطفاً از سرپرست خود بخواهید ثبت نام شما را تأیید کند" msgstr "لطفاً از ادمین خود بخواهید ثبت نام شما را تأیید کند"
#: lms/overrides/user.py:238 #: lms/overrides/user.py:238
msgid "Please check your email for verification" msgid "Please check your email for verification"
@@ -3567,7 +3567,7 @@ msgstr ""
#: frontend/src/components/CourseOutline.vue:312 #: frontend/src/components/CourseOutline.vue:312
msgid "Please enroll for this course to view this lesson" msgid "Please enroll for this course to view this lesson"
msgstr "" msgstr "لطفا برای مشاهده این درس در این دوره ثبت نام کنید"
#: frontend/src/components/Quiz.vue:13 #: frontend/src/components/Quiz.vue:13
msgid "Please ensure that you complete all the questions in {0} minutes." msgid "Please ensure that you complete all the questions in {0} minutes."
@@ -4778,7 +4778,7 @@ msgstr ""
#: frontend/src/pages/SCORMChapter.vue:198 #: frontend/src/pages/SCORMChapter.vue:198
msgid "This is a chapter in the course {0}" msgid "This is a chapter in the course {0}"
msgstr "" msgstr "این یک فصل از دوره {0} است"
#: lms/lms/widgets/CourseOutline.html:62 #: lms/lms/widgets/CourseOutline.html:62
msgid "This lesson is not available for preview. As you are the Instructor of the course only you can see it." msgid "This lesson is not available for preview. As you are the Instructor of the course only you can see it."
@@ -4898,7 +4898,7 @@ msgstr "عنوان"
#: frontend/src/components/Modals/ChapterModal.vue:169 #: frontend/src/components/Modals/ChapterModal.vue:169
msgid "Title is required" msgid "Title is required"
msgstr "" msgstr "عنوان الزامی است"
#. Label of the unavailable_to (Date) field in DocType 'Course Evaluator' #. Label of the unavailable_to (Date) field in DocType 'Course Evaluator'
#: frontend/src/pages/ProfileEvaluator.vue:98 #: frontend/src/pages/ProfileEvaluator.vue:98
@@ -5253,11 +5253,11 @@ msgstr ""
#: frontend/src/components/CourseOutline.vue:311 #: frontend/src/components/CourseOutline.vue:311
msgid "You are not enrolled" msgid "You are not enrolled"
msgstr "" msgstr "شما ثبت نام نکرده اید"
#: frontend/src/pages/SCORMChapter.vue:22 #: frontend/src/pages/SCORMChapter.vue:22
msgid "You are not enrolled in this course. Please enroll to access this lesson." msgid "You are not enrolled in this course. Please enroll to access this lesson."
msgstr "" msgstr "شما در این دوره ثبت نام نکرده اید. لطفا برای دسترسی به این دوره ثبت نام کنید."
#: frontend/src/pages/Courses.vue:134 #: frontend/src/pages/Courses.vue:134
msgid "You can add chapters and lessons to it." msgid "You can add chapters and lessons to it."
@@ -5489,7 +5489,7 @@ msgstr ""
#: lms/lms/doctype/lms_certificate/lms_certificate.py:59 #: lms/lms/doctype/lms_certificate/lms_certificate.py:59
msgid "{0} is already certified for the course {1}" msgid "{0} is already certified for the course {1}"
msgstr "" msgstr "{0} قبلاً برای دوره {1} تایید شده است"
#: lms/lms/notification/certificate_request_reminder/certificate_request_reminder.html:5 #: lms/lms/notification/certificate_request_reminder/certificate_request_reminder.html:5
msgid "{0} is your evaluator" msgid "{0} is your evaluator"

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Frappe LMS VERSION\n" "Project-Id-Version: Frappe LMS VERSION\n"
"Report-Msgid-Bugs-To: jannat@frappe.io\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n"
"POT-Creation-Date: 2024-11-15 16:04+0000\n" "POT-Creation-Date: 2024-11-22 16:05+0000\n"
"PO-Revision-Date: 2024-11-15 16:04+0000\n" "PO-Revision-Date: 2024-11-22 16:05+0000\n"
"Last-Translator: jannat@frappe.io\n" "Last-Translator: jannat@frappe.io\n"
"Language-Team: jannat@frappe.io\n" "Language-Team: jannat@frappe.io\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@@ -20,6 +20,11 @@ msgstr ""
msgid " Please evaluate and grade it." msgid " Please evaluate and grade it."
msgstr "" msgstr ""
#: frontend/src/pages/Programs.vue:41
#, python-format
msgid "% completed"
msgstr ""
#. Paragraph text in the LMS Workspace #. Paragraph text in the LMS Workspace
#: lms/lms/workspace/lms/lms.json #: lms/lms/workspace/lms/lms.json
msgid "<a href=\"/app/lms-settings/LMS%20Settings\">LMS Settings</a>" msgid "<a href=\"/app/lms-settings/LMS%20Settings\">LMS Settings</a>"
@@ -97,7 +102,8 @@ msgstr ""
#: frontend/src/components/BatchStudents.vue:6 #: frontend/src/components/BatchStudents.vue:6
#: frontend/src/components/Categories.vue:26 #: frontend/src/components/Categories.vue:26
#: frontend/src/components/LiveClass.vue:11 #: frontend/src/components/LiveClass.vue:11
#: frontend/src/components/Members.vue:43 #: frontend/src/components/Members.vue:43 frontend/src/pages/ProgramForm.vue:30
#: frontend/src/pages/ProgramForm.vue:91 frontend/src/pages/ProgramForm.vue:136
msgid "Add" msgid "Add"
msgstr "" msgstr ""
@@ -127,12 +133,20 @@ msgstr ""
msgid "Add a Student" msgid "Add a Student"
msgstr "" msgstr ""
#: frontend/src/components/OnboardingBanner.vue:50
msgid "Add a chapter"
msgstr ""
#: frontend/src/components/Modals/BatchCourseModal.vue:5 #: frontend/src/components/Modals/BatchCourseModal.vue:5
msgid "Add a course" msgid "Add a course"
msgstr "" msgstr ""
#: frontend/src/components/OnboardingBanner.vue:73
msgid "Add a lesson"
msgstr ""
#: frontend/src/components/Modals/Question.vue:141 #: frontend/src/components/Modals/Question.vue:141
#: frontend/src/pages/QuizForm.vue:181 #: frontend/src/pages/QuizForm.vue:182
msgid "Add a new question" msgid "Add a new question"
msgstr "" msgstr ""
@@ -148,7 +162,7 @@ msgstr ""
msgid "Add an existing question" msgid "Add an existing question"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_question/lms_question.py:60 #: lms/lms/doctype/lms_question/lms_question.py:66
msgid "Add at least one possible answer for this question: {0}" msgid "Add at least one possible answer for this question: {0}"
msgstr "" msgstr ""
@@ -251,6 +265,14 @@ msgstr ""
msgid "Amount Field" msgid "Amount Field"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:70
msgid "Amount and currency are required for paid batches."
msgstr ""
#: lms/lms/doctype/lms_course/lms_course.py:57
msgid "Amount and currency are required for paid courses."
msgstr ""
#. Label of the amount_with_gst (Currency) field in DocType 'LMS Payment' #. Label of the amount_with_gst (Currency) field in DocType 'LMS Payment'
#: lms/lms/doctype/lms_payment/lms_payment.json #: lms/lms/doctype/lms_payment/lms_payment.json
msgid "Amount with GST" msgid "Amount with GST"
@@ -344,7 +366,7 @@ msgstr ""
msgid "Assessment added successfully" msgid "Assessment added successfully"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:75 #: lms/lms/doctype/lms_batch/lms_batch.py:80
msgid "Assessment {0} has already been added to this batch." msgid "Assessment {0} has already been added to this batch."
msgstr "" msgstr ""
@@ -395,7 +417,7 @@ msgstr ""
msgid "Assignment will appear at the bottom of the lesson." msgid "Assignment will appear at the bottom of the lesson."
msgstr "" msgstr ""
#: lms/lms/doctype/lms_question/lms_question.py:42 #: lms/lms/doctype/lms_question/lms_question.py:43
msgid "At least one option must be correct for this question." msgid "At least one option must be correct for this question."
msgstr "" msgstr ""
@@ -538,7 +560,7 @@ msgstr ""
msgid "Batch Updated" msgid "Batch Updated"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:40 #: lms/lms/doctype/lms_batch/lms_batch.py:41
msgid "Batch end date cannot be before the batch start date" msgid "Batch end date cannot be before the batch start date"
msgstr "" msgstr ""
@@ -725,11 +747,11 @@ msgstr ""
msgid "Chapter Reference" msgid "Chapter Reference"
msgstr "" msgstr ""
#: frontend/src/components/Modals/ChapterModal.vue:149 #: frontend/src/components/Modals/ChapterModal.vue:154
msgid "Chapter added successfully" msgid "Chapter added successfully"
msgstr "" msgstr ""
#: frontend/src/components/Modals/ChapterModal.vue:193 #: frontend/src/components/Modals/ChapterModal.vue:198
msgid "Chapter updated successfully" msgid "Chapter updated successfully"
msgstr "" msgstr ""
@@ -762,7 +784,7 @@ msgstr ""
msgid "Choices" msgid "Choices"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:578 lms/templates/quiz/quiz.html:53 #: frontend/src/components/Quiz.vue:581 lms/templates/quiz/quiz.html:53
msgid "Choose all answers that apply" msgid "Choose all answers that apply"
msgstr "" msgstr ""
@@ -770,7 +792,7 @@ msgstr ""
msgid "Choose an icon" msgid "Choose an icon"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:579 lms/templates/quiz/quiz.html:53 #: frontend/src/components/Quiz.vue:582 lms/templates/quiz/quiz.html:53
msgid "Choose one answer" msgid "Choose one answer"
msgstr "" msgstr ""
@@ -986,7 +1008,7 @@ msgid "Contact the Administrator to enroll for this course."
msgstr "" msgstr ""
#. Label of the content (Text) field in DocType 'Course Lesson' #. Label of the content (Text) field in DocType 'Course Lesson'
#: frontend/src/pages/LessonForm.vue:58 #: frontend/src/pages/LessonForm.vue:62
#: lms/lms/doctype/course_lesson/course_lesson.json #: lms/lms/doctype/course_lesson/course_lesson.json
msgid "Content" msgid "Content"
msgstr "" msgstr ""
@@ -1055,6 +1077,7 @@ msgstr ""
#. Label of the course (Link) field in DocType 'LMS Enrollment' #. Label of the course (Link) field in DocType 'LMS Enrollment'
#. Label of the course (Link) field in DocType 'LMS Exercise' #. Label of the course (Link) field in DocType 'LMS Exercise'
#. Label of the course (Link) field in DocType 'LMS Mentor Request' #. Label of the course (Link) field in DocType 'LMS Mentor Request'
#. Label of the course (Link) field in DocType 'LMS Program Course'
#. Label of the course (Link) field in DocType 'LMS Quiz' #. Label of the course (Link) field in DocType 'LMS Quiz'
#. Label of the course (Link) field in DocType 'LMS Quiz Submission' #. Label of the course (Link) field in DocType 'LMS Quiz Submission'
#. Label of the course (Link) field in DocType 'Related Courses' #. Label of the course (Link) field in DocType 'Related Courses'
@@ -1084,6 +1107,7 @@ msgstr ""
#: lms/lms/doctype/lms_enrollment/lms_enrollment.json #: lms/lms/doctype/lms_enrollment/lms_enrollment.json
#: lms/lms/doctype/lms_exercise/lms_exercise.json #: lms/lms/doctype/lms_exercise/lms_exercise.json
#: lms/lms/doctype/lms_mentor_request/lms_mentor_request.json #: lms/lms/doctype/lms_mentor_request/lms_mentor_request.json
#: lms/lms/doctype/lms_program_course/lms_program_course.json
#: lms/lms/doctype/lms_quiz/lms_quiz.json #: lms/lms/doctype/lms_quiz/lms_quiz.json
#: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json #: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json
#: lms/lms/doctype/related_courses/related_courses.json #: lms/lms/doctype/related_courses/related_courses.json
@@ -1112,6 +1136,7 @@ msgstr ""
#. Name of a role #. Name of a role
#: frontend/src/pages/ProfileRoles.vue:16 #: frontend/src/pages/ProfileRoles.vue:16
#: lms/lms/doctype/lms_course/lms_course.json #: lms/lms/doctype/lms_course/lms_course.json
#: lms/lms/doctype/lms_program/lms_program.json
#: lms/lms/doctype/lms_question/lms_question.json #: lms/lms/doctype/lms_question/lms_question.json
#: lms/lms/doctype/lms_quiz/lms_quiz.json #: lms/lms/doctype/lms_quiz/lms_quiz.json
msgid "Course Creator" msgid "Course Creator"
@@ -1182,22 +1207,33 @@ msgstr ""
#. Label of the course_title (Data) field in DocType 'Course Chapter' #. Label of the course_title (Data) field in DocType 'Course Chapter'
#. Label of the course_title (Data) field in DocType 'LMS Certificate' #. Label of the course_title (Data) field in DocType 'LMS Certificate'
#. Label of the course_title (Data) field in DocType 'LMS Certificate Request' #. Label of the course_title (Data) field in DocType 'LMS Certificate Request'
#. Label of the course_title (Data) field in DocType 'LMS Program Course'
#: lms/lms/doctype/batch_course/batch_course.json #: lms/lms/doctype/batch_course/batch_course.json
#: lms/lms/doctype/course_chapter/course_chapter.json #: lms/lms/doctype/course_chapter/course_chapter.json
#: lms/lms/doctype/lms_certificate/lms_certificate.json #: lms/lms/doctype/lms_certificate/lms_certificate.json
#: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json #: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json
#: lms/lms/doctype/lms_program_course/lms_program_course.json
msgid "Course Title" msgid "Course Title"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:340 #: frontend/src/pages/ProgramForm.vue:226
msgid "Course added to program"
msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:345
msgid "Course already added to the batch." msgid "Course already added to the batch."
msgstr "" msgstr ""
#: frontend/src/pages/CourseForm.vue:457 #: frontend/src/pages/CourseForm.vue:460
msgid "Course deleted successfully" msgid "Course deleted successfully"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:58 #: frontend/src/pages/ProgramForm.vue:295
msgid "Course moved successfully"
msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:59
#: lms/lms/doctype/lms_program/lms_program.py:19
msgid "Course {0} has already been added to this batch." msgid "Course {0} has already been added to this batch."
msgstr "" msgstr ""
@@ -1232,6 +1268,7 @@ msgid "Cover Image"
msgstr "" msgstr ""
#: frontend/src/components/Modals/ChapterModal.vue:9 #: frontend/src/components/Modals/ChapterModal.vue:9
#: frontend/src/pages/Programs.vue:99
msgid "Create" msgid "Create"
msgstr "" msgstr ""
@@ -1247,7 +1284,7 @@ msgstr ""
msgid "Create a Batch" msgid "Create a Batch"
msgstr "" msgstr ""
#: frontend/src/pages/Courses.vue:131 lms/templates/onboarding_header.html:19 #: frontend/src/pages/Courses.vue:132 lms/templates/onboarding_header.html:19
msgid "Create a Course" msgid "Create a Course"
msgstr "" msgstr ""
@@ -1255,6 +1292,10 @@ msgstr ""
msgid "Create a Live Class" msgid "Create a Live Class"
msgstr "" msgstr ""
#: frontend/src/components/OnboardingBanner.vue:27
msgid "Create a course"
msgstr ""
#: frontend/src/components/Modals/Question.vue:31 #: frontend/src/components/Modals/Question.vue:31
msgid "Create a new question" msgid "Create a new question"
msgstr "" msgstr ""
@@ -1358,7 +1399,7 @@ msgstr ""
#: frontend/src/components/CourseOutline.vue:235 #: frontend/src/components/CourseOutline.vue:235
#: frontend/src/components/CourseOutline.vue:293 #: frontend/src/components/CourseOutline.vue:293
#: frontend/src/pages/CourseForm.vue:15 frontend/src/pages/CourseForm.vue:470 #: frontend/src/pages/CourseForm.vue:15 frontend/src/pages/CourseForm.vue:473
msgid "Delete" msgid "Delete"
msgstr "" msgstr ""
@@ -1366,7 +1407,7 @@ msgstr ""
msgid "Delete Chapter" msgid "Delete Chapter"
msgstr "" msgstr ""
#: frontend/src/pages/CourseForm.vue:464 #: frontend/src/pages/CourseForm.vue:467
msgid "Delete Course" msgid "Delete Course"
msgstr "" msgstr ""
@@ -1378,7 +1419,7 @@ msgstr ""
msgid "Delete this lesson?" msgid "Delete this lesson?"
msgstr "" msgstr ""
#: frontend/src/pages/CourseForm.vue:465 #: frontend/src/pages/CourseForm.vue:468
msgid "Deleting the course will also delete all its chapters and lessons. Are you sure you want to delete this course?" msgid "Deleting the course will also delete all its chapters and lessons. Are you sure you want to delete this course?"
msgstr "" msgstr ""
@@ -1468,7 +1509,7 @@ msgstr ""
msgid "Dream Companies" msgid "Dream Companies"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_question/lms_question.py:32 #: lms/lms/doctype/lms_question/lms_question.py:33
msgid "Duplicate options found for this question." msgid "Duplicate options found for this question."
msgstr "" msgstr ""
@@ -1506,7 +1547,7 @@ msgstr ""
#: frontend/src/components/CourseCardOverlay.vue:86 #: frontend/src/components/CourseCardOverlay.vue:86
#: frontend/src/components/Modals/ChapterModal.vue:9 #: frontend/src/components/Modals/ChapterModal.vue:9
#: frontend/src/pages/JobDetail.vue:31 frontend/src/pages/Lesson.vue:65 #: frontend/src/pages/JobDetail.vue:31 frontend/src/pages/Lesson.vue:65
#: frontend/src/pages/Profile.vue:32 #: frontend/src/pages/Profile.vue:32 frontend/src/pages/Programs.vue:55
msgid "Edit" msgid "Edit"
msgstr "" msgstr ""
@@ -1519,7 +1560,7 @@ msgstr ""
msgid "Edit Profile" msgid "Edit Profile"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:180 #: frontend/src/pages/QuizForm.vue:181
msgid "Edit the question" msgid "Edit the question"
msgstr "" msgstr ""
@@ -1580,6 +1621,15 @@ msgstr ""
msgid "Enable Google API in Google Settings to send calendar invites for evaluations." msgid "Enable Google API in Google Settings to send calendar invites for evaluations."
msgstr "" msgstr ""
#. Label of the enable_learning_paths (Check) field in DocType 'LMS Settings'
#: lms/lms/doctype/lms_settings/lms_settings.json
msgid "Enable Learning Paths"
msgstr ""
#: frontend/src/components/Modals/ChapterModal.vue:24
msgid "Enable this only if you want to upload a SCORM package as a chapter."
msgstr ""
#. Label of the enabled (Check) field in DocType 'LMS Badge' #. Label of the enabled (Check) field in DocType 'LMS Badge'
#: lms/lms/doctype/lms_badge/lms_badge.json #: lms/lms/doctype/lms_badge/lms_badge.json
msgid "Enabled" msgid "Enabled"
@@ -1632,7 +1682,7 @@ msgstr ""
msgid "Enrolled successfully" msgid "Enrolled successfully"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:98 #: lms/lms/doctype/lms_batch/lms_batch.py:103
msgid "Enrollment Confirmation for the Next Training Batch" msgid "Enrollment Confirmation for the Next Training Batch"
msgstr "" msgstr ""
@@ -1641,7 +1691,7 @@ msgstr ""
msgid "Enrollment Count" msgid "Enrollment Count"
msgstr "" msgstr ""
#: lms/lms/utils.py:1702 #: lms/lms/utils.py:1705
msgid "Enrollment Failed" msgid "Enrollment Failed"
msgstr "" msgstr ""
@@ -1670,14 +1720,14 @@ msgid "Enter the correct answer"
msgstr "" msgstr ""
#: frontend/src/components/Modals/AnnouncementModal.vue:105 #: frontend/src/components/Modals/AnnouncementModal.vue:105
#: frontend/src/components/Modals/ChapterModal.vue:154 #: frontend/src/components/Modals/ChapterModal.vue:159
#: frontend/src/components/Modals/ChapterModal.vue:161 #: frontend/src/components/Modals/ChapterModal.vue:166
#: frontend/src/components/Modals/ChapterModal.vue:197 #: frontend/src/components/Modals/ChapterModal.vue:202
#: frontend/src/components/Modals/Question.vue:246 #: frontend/src/components/Modals/Question.vue:246
#: frontend/src/components/Modals/Question.vue:266 #: frontend/src/components/Modals/Question.vue:266
#: frontend/src/components/Modals/Question.vue:323 #: frontend/src/components/Modals/Question.vue:323
#: frontend/src/pages/Billing.vue:264 frontend/src/pages/QuizForm.vue:349 #: frontend/src/pages/Billing.vue:264 frontend/src/pages/QuizForm.vue:350
#: frontend/src/pages/QuizForm.vue:364 #: frontend/src/pages/QuizForm.vue:365
#: frontend/src/pages/QuizSubmission.vue:117 #: frontend/src/pages/QuizSubmission.vue:117
msgid "Error" msgid "Error"
msgstr "" msgstr ""
@@ -1706,7 +1756,7 @@ msgstr ""
msgid "Evaluation Request" msgid "Evaluation Request"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:82 #: lms/lms/doctype/lms_batch/lms_batch.py:87
msgid "Evaluation end date cannot be less than the batch end date." msgid "Evaluation end date cannot be less than the batch end date."
msgstr "" msgstr ""
@@ -1872,7 +1922,7 @@ msgstr ""
msgid "Flexible Time" msgid "Flexible Time"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:462 #: frontend/src/pages/QuizForm.vue:463
msgid "Form to create and edit quizzes" msgid "Form to create and edit quizzes"
msgstr "" msgstr ""
@@ -1920,7 +1970,9 @@ msgid "From Date"
msgstr "" msgstr ""
#. Label of the full_name (Data) field in DocType 'Invite Request' #. Label of the full_name (Data) field in DocType 'Invite Request'
#. Label of the full_name (Data) field in DocType 'LMS Program Member'
#: lms/lms/doctype/invite_request/invite_request.json #: lms/lms/doctype/invite_request/invite_request.json
#: lms/lms/doctype/lms_program_member/lms_program_member.json
#: lms/templates/signup-form.html:5 #: lms/templates/signup-form.html:5
msgid "Full Name" msgid "Full Name"
msgstr "" msgstr ""
@@ -1952,6 +2004,11 @@ msgstr ""
msgid "GSTIN" msgid "GSTIN"
msgstr "" msgstr ""
#. Label of the general_tab (Tab Break) field in DocType 'LMS Settings'
#: lms/lms/doctype/lms_settings/lms_settings.json
msgid "General"
msgstr ""
#: lms/lms/doctype/lms_certificate_request/lms_certificate_request.js:18 #: lms/lms/doctype/lms_certificate_request/lms_certificate_request.js:18
msgid "Generate Google Meet Link" msgid "Generate Google Meet Link"
msgstr "" msgstr ""
@@ -2083,7 +2140,7 @@ msgstr ""
msgid "I am unavailable" msgid "I am unavailable"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:383 #: frontend/src/pages/QuizForm.vue:384
msgid "ID" msgid "ID"
msgstr "" msgstr ""
@@ -2224,7 +2281,7 @@ msgstr ""
#. Label of the instructor_notes (Markdown Editor) field in DocType 'Course #. Label of the instructor_notes (Markdown Editor) field in DocType 'Course
#. Lesson' #. Lesson'
#: frontend/src/pages/Lesson.vue:128 frontend/src/pages/LessonForm.vue:38 #: frontend/src/pages/Lesson.vue:128 frontend/src/pages/LessonForm.vue:42
#: lms/lms/doctype/course_lesson/course_lesson.json #: lms/lms/doctype/course_lesson/course_lesson.json
msgid "Instructor Notes" msgid "Instructor Notes"
msgstr "" msgstr ""
@@ -2300,7 +2357,6 @@ msgstr ""
#. Label of the is_scorm_package (Check) field in DocType 'Course Chapter' #. Label of the is_scorm_package (Check) field in DocType 'Course Chapter'
#. Label of the is_scorm_package (Check) field in DocType 'Course Lesson' #. Label of the is_scorm_package (Check) field in DocType 'Course Lesson'
#: frontend/src/components/Modals/ChapterModal.vue:26
#: lms/lms/doctype/course_chapter/course_chapter.json #: lms/lms/doctype/course_chapter/course_chapter.json
#: lms/lms/doctype/course_lesson/course_lesson.json #: lms/lms/doctype/course_lesson/course_lesson.json
msgid "Is SCORM Package" msgid "Is SCORM Package"
@@ -2330,6 +2386,10 @@ msgstr ""
msgid "Items in Sidebar" msgid "Items in Sidebar"
msgstr "" msgstr ""
#: frontend/src/pages/ProgramForm.vue:269
msgid "Items removed successfully"
msgstr ""
#: lms/templates/signup-form.html:6 #: lms/templates/signup-form.html:6
msgid "Jane Doe" msgid "Jane Doe"
msgstr "" msgstr ""
@@ -2529,6 +2589,21 @@ msgstr ""
msgid "LMS Payment" msgid "LMS Payment"
msgstr "" msgstr ""
#. Name of a DocType
#: lms/lms/doctype/lms_program/lms_program.json
msgid "LMS Program"
msgstr ""
#. Name of a DocType
#: lms/lms/doctype/lms_program_course/lms_program_course.json
msgid "LMS Program Course"
msgstr ""
#. Name of a DocType
#: lms/lms/doctype/lms_program_member/lms_program_member.json
msgid "LMS Program Member"
msgstr ""
#. Name of a DocType #. Name of a DocType
#: lms/lms/doctype/lms_question/lms_question.json #: lms/lms/doctype/lms_question/lms_question.json
msgid "LMS Question" msgid "LMS Question"
@@ -2588,6 +2663,7 @@ msgstr ""
#: lms/lms/doctype/lms_live_class/lms_live_class.json #: lms/lms/doctype/lms_live_class/lms_live_class.json
#: lms/lms/doctype/lms_quiz/lms_quiz.json #: lms/lms/doctype/lms_quiz/lms_quiz.json
#: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json #: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json
#: lms/lms/doctype/lms_settings/lms_settings.json
#: lms/lms/doctype/lms_source/lms_source.json #: lms/lms/doctype/lms_source/lms_source.json
#: lms/lms/doctype/user_skill/user_skill.json #: lms/lms/doctype/user_skill/user_skill.json
msgid "LMS Student" msgid "LMS Student"
@@ -2810,7 +2886,7 @@ msgstr ""
#. Label of the marks (Int) field in DocType 'LMS Quiz Result' #. Label of the marks (Int) field in DocType 'LMS Quiz Result'
#: frontend/src/components/Modals/Question.vue:50 #: frontend/src/components/Modals/Question.vue:50
#: frontend/src/components/Modals/Question.vue:96 #: frontend/src/components/Modals/Question.vue:96
#: frontend/src/components/Quiz.vue:94 frontend/src/pages/QuizForm.vue:393 #: frontend/src/components/Quiz.vue:94 frontend/src/pages/QuizForm.vue:394
#: frontend/src/pages/QuizSubmission.vue:52 #: frontend/src/pages/QuizSubmission.vue:52
#: lms/lms/doctype/lms_quiz_question/lms_quiz_question.json #: lms/lms/doctype/lms_quiz_question/lms_quiz_question.json
#: lms/lms/doctype/lms_quiz_result/lms_quiz_result.json #: lms/lms/doctype/lms_quiz_result/lms_quiz_result.json
@@ -2865,6 +2941,7 @@ msgstr ""
#. Option for the 'Role' (Select) field in DocType 'LMS Enrollment' #. Option for the 'Role' (Select) field in DocType 'LMS Enrollment'
#. Label of the member (Link) field in DocType 'LMS Mentor Request' #. Label of the member (Link) field in DocType 'LMS Mentor Request'
#. Label of the member (Link) field in DocType 'LMS Payment' #. Label of the member (Link) field in DocType 'LMS Payment'
#. Label of the member (Link) field in DocType 'LMS Program Member'
#. Label of the member (Link) field in DocType 'LMS Quiz Submission' #. Label of the member (Link) field in DocType 'LMS Quiz Submission'
#: frontend/src/pages/QuizSubmission.vue:27 #: frontend/src/pages/QuizSubmission.vue:27
#: frontend/src/pages/QuizSubmissionList.vue:77 #: frontend/src/pages/QuizSubmissionList.vue:77
@@ -2879,6 +2956,7 @@ msgstr ""
#: lms/lms/doctype/lms_enrollment/lms_enrollment.json #: lms/lms/doctype/lms_enrollment/lms_enrollment.json
#: lms/lms/doctype/lms_mentor_request/lms_mentor_request.json #: lms/lms/doctype/lms_mentor_request/lms_mentor_request.json
#: lms/lms/doctype/lms_payment/lms_payment.json #: lms/lms/doctype/lms_payment/lms_payment.json
#: lms/lms/doctype/lms_program_member/lms_program_member.json
#: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json #: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json
#: lms/lms/report/course_progress_summary/course_progress_summary.py:64 #: lms/lms/report/course_progress_summary/course_progress_summary.py:64
msgid "Member" msgid "Member"
@@ -2928,6 +3006,14 @@ msgstr ""
msgid "Member Type" msgid "Member Type"
msgstr "" msgstr ""
#: frontend/src/pages/ProgramForm.vue:248
msgid "Member added to program"
msgstr ""
#: lms/lms/doctype/lms_program/lms_program.py:29
msgid "Member {0} has already been added to this batch."
msgstr ""
#. Group in LMS Batch Old's connections #. Group in LMS Batch Old's connections
#: lms/lms/doctype/lms_batch_old/lms_batch_old.json #: lms/lms/doctype/lms_batch_old/lms_batch_old.json
msgid "Members" msgid "Members"
@@ -3000,6 +3086,10 @@ msgstr ""
msgid "Milestones" msgid "Milestones"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_question/lms_question.py:48
msgid "Minimum two options are required for multiple choice questions."
msgstr ""
#. Name of a role #. Name of a role
#: frontend/src/pages/ProfileRoles.vue:10 #: frontend/src/pages/ProfileRoles.vue:10
#: lms/lms/doctype/course_evaluator/course_evaluator.json #: lms/lms/doctype/course_evaluator/course_evaluator.json
@@ -3011,6 +3101,7 @@ msgstr ""
#: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json #: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json
#: lms/lms/doctype/lms_enrollment/lms_enrollment.json #: lms/lms/doctype/lms_enrollment/lms_enrollment.json
#: lms/lms/doctype/lms_live_class/lms_live_class.json #: lms/lms/doctype/lms_live_class/lms_live_class.json
#: lms/lms/doctype/lms_program/lms_program.json
#: lms/lms/doctype/lms_question/lms_question.json #: lms/lms/doctype/lms_question/lms_question.json
#: lms/lms/doctype/lms_quiz/lms_quiz.json #: lms/lms/doctype/lms_quiz/lms_quiz.json
#: lms/lms/doctype/lms_source/lms_source.json #: lms/lms/doctype/lms_source/lms_source.json
@@ -3055,8 +3146,8 @@ msgid "My calendar"
msgstr "" msgstr ""
#. Option for the 'Event' (Select) field in DocType 'LMS Badge' #. Option for the 'Event' (Select) field in DocType 'LMS Badge'
#: frontend/src/pages/Batches.vue:30 frontend/src/pages/Courses.vue:44 #: frontend/src/pages/Batches.vue:30 frontend/src/pages/Courses.vue:45
#: lms/lms/doctype/lms_badge/lms_badge.json #: frontend/src/pages/Programs.vue:14 lms/lms/doctype/lms_badge/lms_badge.json
msgid "New" msgid "New"
msgstr "" msgstr ""
@@ -3080,11 +3171,23 @@ msgstr ""
msgid "New Job Applicant" msgid "New Job Applicant"
msgstr "" msgstr ""
#: frontend/src/pages/Programs.vue:96
msgid "New Program"
msgstr ""
#: frontend/src/pages/ProgramForm.vue:132
msgid "New Program Course"
msgstr ""
#: frontend/src/pages/ProgramForm.vue:133
msgid "New Program Member"
msgstr ""
#: frontend/src/pages/QuizForm.vue:122 #: frontend/src/pages/QuizForm.vue:122
msgid "New Question" msgid "New Question"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:453 frontend/src/pages/QuizForm.vue:461 #: frontend/src/pages/QuizForm.vue:454 frontend/src/pages/QuizForm.vue:462
#: frontend/src/pages/Quizzes.vue:18 #: frontend/src/pages/Quizzes.vue:18
msgid "New Quiz" msgid "New Quiz"
msgstr "" msgstr ""
@@ -3147,10 +3250,14 @@ msgstr ""
msgid "No courses created" msgid "No courses created"
msgstr "" msgstr ""
#: frontend/src/pages/Courses.vue:146 #: frontend/src/pages/Courses.vue:147
msgid "No courses found" msgid "No courses found"
msgstr "" msgstr ""
#: frontend/src/pages/Programs.vue:72
msgid "No courses in this program"
msgstr ""
#: lms/templates/courses_under_review.html:14 #: lms/templates/courses_under_review.html:14
msgid "No courses under review" msgid "No courses under review"
msgstr "" msgstr ""
@@ -3167,6 +3274,10 @@ msgstr ""
msgid "No live classes scheduled" msgid "No live classes scheduled"
msgstr "" msgstr ""
#: frontend/src/pages/Programs.vue:82
msgid "No programs found"
msgstr ""
#: frontend/src/pages/Quizzes.vue:56 #: frontend/src/pages/Quizzes.vue:56
msgid "No quizzes found" msgid "No quizzes found"
msgstr "" msgstr ""
@@ -3187,7 +3298,7 @@ msgstr ""
msgid "No {0} batches" msgid "No {0} batches"
msgstr "" msgstr ""
#: frontend/src/pages/Courses.vue:106 #: frontend/src/pages/Courses.vue:107
msgid "No {0} courses" msgid "No {0} courses"
msgstr "" msgstr ""
@@ -3275,15 +3386,19 @@ msgstr ""
msgid "Online" msgid "Online"
msgstr "" msgstr ""
#: frontend/src/pages/ProgramForm.vue:156
msgid "Only courses for which self learning is disabled can be added to program."
msgstr ""
#: lms/templates/assignment.html:6 #: lms/templates/assignment.html:6
msgid "Only files of type {0} will be accepted." msgid "Only files of type {0} will be accepted."
msgstr "" msgstr ""
#: frontend/src/pages/CourseForm.vue:494 frontend/src/utils/index.js:518 #: frontend/src/pages/CourseForm.vue:497 frontend/src/utils/index.js:518
msgid "Only image file is allowed." msgid "Only image file is allowed."
msgstr "" msgstr ""
#: frontend/src/components/Modals/ChapterModal.vue:223 #: frontend/src/components/Modals/ChapterModal.vue:220
msgid "Only zip files are allowed" msgid "Only zip files are allowed"
msgstr "" msgstr ""
@@ -3559,7 +3674,11 @@ msgstr ""
msgid "Please click on the following button to set your new password" msgid "Please click on the following button to set your new password"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:251 #: lms/lms/utils.py:1817 lms/lms/utils.py:1821
msgid "Please complete the previous courses in the program to enroll in this course."
msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:256
msgid "Please enable Zoom Settings to use this feature." msgid "Please enable Zoom Settings to use this feature."
msgstr "" msgstr ""
@@ -3571,11 +3690,19 @@ msgstr ""
msgid "Please ensure that you complete all the questions in {0} minutes." msgid "Please ensure that you complete all the questions in {0} minutes."
msgstr "" msgstr ""
#: frontend/src/components/Modals/LiveClassModal.vue:164
msgid "Please enter a title."
msgstr ""
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.py:38 #: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.py:38
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.py:98 #: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.py:98
msgid "Please enter a valid URL." msgid "Please enter a valid URL."
msgstr "" msgstr ""
#: frontend/src/components/Modals/LiveClassModal.vue:176
msgid "Please enter a valid time in the format HH:mm."
msgstr ""
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.py:92 #: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.py:92
msgid "Please enter the URL for assignment submission." msgid "Please enter the URL for assignment submission."
msgstr "" msgstr ""
@@ -3584,11 +3711,11 @@ msgstr ""
msgid "Please enter your answer" msgid "Please enter your answer"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:65 #: lms/lms/doctype/lms_batch/lms_batch.py:66
msgid "Please install the Payments app to create a paid batches." msgid "Please install the Payments app to create a paid batches."
msgstr "" msgstr ""
#: lms/lms/doctype/lms_course/lms_course.py:52 #: lms/lms/doctype/lms_course/lms_course.py:53
msgid "Please install the Payments app to create a paid courses." msgid "Please install the Payments app to create a paid courses."
msgstr "" msgstr ""
@@ -3613,11 +3740,31 @@ msgstr ""
msgid "Please prepare well and be on time for the evaluations." msgid "Please prepare well and be on time for the evaluations."
msgstr "" msgstr ""
#: frontend/src/components/Modals/LiveClassModal.vue:167
msgid "Please select a date."
msgstr ""
#: frontend/src/components/Modals/LiveClassModal.vue:191
msgid "Please select a duration."
msgstr ""
#: frontend/src/components/Modals/LiveClassModal.vue:188
msgid "Please select a future date and time."
msgstr ""
#: frontend/src/components/Modals/LiveClassModal.vue:170
msgid "Please select a time."
msgstr ""
#: frontend/src/components/Modals/LiveClassModal.vue:173
msgid "Please select a timezone."
msgstr ""
#: lms/templates/emails/job_report.html:6 #: lms/templates/emails/job_report.html:6
msgid "Please take appropriate action at {0}" msgid "Please take appropriate action at {0}"
msgstr "" msgstr ""
#: frontend/src/components/Modals/ChapterModal.vue:172 #: frontend/src/components/Modals/ChapterModal.vue:177
msgid "Please upload a SCORM package" msgid "Please upload a SCORM package"
msgstr "" msgstr ""
@@ -3754,8 +3901,30 @@ msgstr ""
msgid "Profile Image" msgid "Profile Image"
msgstr "" msgstr ""
#: frontend/src/pages/ProgramForm.vue:154
msgid "Program Course"
msgstr ""
#. Label of the program_courses (Table) field in DocType 'LMS Program'
#: frontend/src/pages/ProgramForm.vue:17
#: lms/lms/doctype/lms_program/lms_program.json
msgid "Program Courses"
msgstr ""
#: frontend/src/pages/ProgramForm.vue:169
msgid "Program Member"
msgstr ""
#. Label of the program_members (Table) field in DocType 'LMS Program'
#: frontend/src/pages/ProgramForm.vue:78
#: lms/lms/doctype/lms_program/lms_program.json
msgid "Program Members"
msgstr ""
#. Label of the progress (Float) field in DocType 'LMS Enrollment' #. Label of the progress (Float) field in DocType 'LMS Enrollment'
#. Label of the progress (Int) field in DocType 'LMS Program Member'
#: lms/lms/doctype/lms_enrollment/lms_enrollment.json #: lms/lms/doctype/lms_enrollment/lms_enrollment.json
#: lms/lms/doctype/lms_program_member/lms_program_member.json
msgid "Progress" msgid "Progress"
msgstr "" msgstr ""
@@ -3805,7 +3974,7 @@ msgstr ""
#. Label of the question (Text) field in DocType 'LMS Quiz Result' #. Label of the question (Text) field in DocType 'LMS Quiz Result'
#: frontend/src/components/Modals/Question.vue:38 #: frontend/src/components/Modals/Question.vue:38
#: frontend/src/pages/AssignmentSubmission.vue:26 #: frontend/src/pages/AssignmentSubmission.vue:26
#: frontend/src/pages/QuizForm.vue:388 #: frontend/src/pages/QuizForm.vue:389
#: lms/lms/doctype/course_lesson/course_lesson.json #: lms/lms/doctype/course_lesson/course_lesson.json
#: lms/lms/doctype/lms_assignment/lms_assignment.json #: lms/lms/doctype/lms_assignment/lms_assignment.json
#: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json #: lms/lms/doctype/lms_assignment_submission/lms_assignment_submission.json
@@ -3851,7 +4020,7 @@ msgstr ""
msgid "Questions" msgid "Questions"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:430 #: frontend/src/pages/QuizForm.vue:431
msgid "Questions deleted successfully" msgid "Questions deleted successfully"
msgstr "" msgstr ""
@@ -3889,7 +4058,7 @@ msgstr ""
msgid "Quiz Title" msgid "Quiz Title"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:342 #: frontend/src/pages/QuizForm.vue:343
msgid "Quiz created successfully" msgid "Quiz created successfully"
msgstr "" msgstr ""
@@ -3897,7 +4066,7 @@ msgstr ""
msgid "Quiz is not available to Guest users. Please login to continue." msgid "Quiz is not available to Guest users. Please login to continue."
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:361 #: frontend/src/pages/QuizForm.vue:362
msgid "Quiz updated successfully" msgid "Quiz updated successfully"
msgstr "" msgstr ""
@@ -3906,7 +4075,7 @@ msgstr ""
msgid "Quiz will appear at the bottom of the lesson." msgid "Quiz will appear at the bottom of the lesson."
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:441 frontend/src/pages/Quizzes.vue:136 #: frontend/src/pages/QuizForm.vue:442 frontend/src/pages/Quizzes.vue:136
#: frontend/src/pages/Quizzes.vue:146 #: frontend/src/pages/Quizzes.vue:146
msgid "Quizzes" msgid "Quizzes"
msgstr "" msgstr ""
@@ -4063,19 +4232,19 @@ msgstr ""
msgid "Route" msgid "Route"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:194 #: lms/lms/doctype/lms_batch/lms_batch.py:199
msgid "Row #{0} Date cannot be outside the batch duration." msgid "Row #{0} Date cannot be outside the batch duration."
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:189 #: lms/lms/doctype/lms_batch/lms_batch.py:194
msgid "Row #{0} End time cannot be outside the batch duration." msgid "Row #{0} End time cannot be outside the batch duration."
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:171 #: lms/lms/doctype/lms_batch/lms_batch.py:176
msgid "Row #{0} Start time cannot be greater than or equal to end time." msgid "Row #{0} Start time cannot be greater than or equal to end time."
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:180 #: lms/lms/doctype/lms_batch/lms_batch.py:185
msgid "Row #{0} Start time cannot be outside the batch duration." msgid "Row #{0} Start time cannot be outside the batch duration."
msgstr "" msgstr ""
@@ -4093,6 +4262,7 @@ msgid "SCORM"
msgstr "" msgstr ""
#. Label of the scorm_package (Link) field in DocType 'Course Chapter' #. Label of the scorm_package (Link) field in DocType 'Course Chapter'
#: frontend/src/components/Modals/ChapterModal.vue:22
#: lms/lms/doctype/course_chapter/course_chapter.json #: lms/lms/doctype/course_chapter/course_chapter.json
msgid "SCORM Package" msgid "SCORM Package"
msgstr "" msgstr ""
@@ -4115,8 +4285,9 @@ msgstr ""
#: frontend/src/components/QuizPlugin.vue:23 #: frontend/src/components/QuizPlugin.vue:23
#: frontend/src/pages/AssignmentSubmission.vue:7 #: frontend/src/pages/AssignmentSubmission.vue:7
#: frontend/src/pages/BatchForm.vue:8 frontend/src/pages/CourseForm.vue:20 #: frontend/src/pages/BatchForm.vue:8 frontend/src/pages/CourseForm.vue:20
#: frontend/src/pages/JobCreation.vue:8 frontend/src/pages/LessonForm.vue:10 #: frontend/src/pages/JobCreation.vue:8 frontend/src/pages/LessonForm.vue:14
#: frontend/src/pages/QuizForm.vue:34 frontend/src/pages/QuizSubmission.vue:14 #: frontend/src/pages/ProgramForm.vue:7 frontend/src/pages/QuizForm.vue:34
#: frontend/src/pages/QuizSubmission.vue:14
#: lms/public/js/common_functions.js:405 #: lms/public/js/common_functions.js:405
msgid "Save" msgid "Save"
msgstr "" msgstr ""
@@ -4332,6 +4503,10 @@ msgstr ""
msgid "Skip" msgid "Skip"
msgstr "" msgstr ""
#: frontend/src/components/OnboardingBanner.vue:3
msgid "Skip Onboarding"
msgstr ""
#: lms/lms/doctype/course_evaluator/course_evaluator.py:57 #: lms/lms/doctype/course_evaluator/course_evaluator.py:57
msgid "Slot Times are overlapping for some schedules." msgid "Slot Times are overlapping for some schedules."
msgstr "" msgstr ""
@@ -4505,7 +4680,7 @@ msgstr ""
msgid "Student Reviews" msgid "Student Reviews"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:47 #: lms/lms/doctype/lms_batch/lms_batch.py:48
msgid "Student {0} has already been added to this batch." msgid "Student {0} has already been added to this batch."
msgstr "" msgstr ""
@@ -4573,14 +4748,17 @@ msgstr ""
#: frontend/src/components/CourseCardOverlay.vue:161 #: frontend/src/components/CourseCardOverlay.vue:161
#: frontend/src/components/Modals/AnnouncementModal.vue:99 #: frontend/src/components/Modals/AnnouncementModal.vue:99
#: frontend/src/components/Modals/AssessmentModal.vue:73 #: frontend/src/components/Modals/AssessmentModal.vue:73
#: frontend/src/components/Modals/ChapterModal.vue:148 #: frontend/src/components/Modals/ChapterModal.vue:153
#: frontend/src/components/Modals/ChapterModal.vue:193 #: frontend/src/components/Modals/ChapterModal.vue:198
#: frontend/src/components/Modals/Event.vue:255 #: frontend/src/components/Modals/Event.vue:255
#: frontend/src/components/Modals/Event.vue:310 #: frontend/src/components/Modals/Event.vue:310
#: frontend/src/components/Modals/Question.vue:261 #: frontend/src/components/Modals/Question.vue:261
#: frontend/src/components/Modals/Question.vue:312 #: frontend/src/components/Modals/Question.vue:312
#: frontend/src/pages/CourseForm.vue:457 frontend/src/pages/QuizForm.vue:342 #: frontend/src/pages/CourseForm.vue:460 frontend/src/pages/ProgramForm.vue:226
#: frontend/src/pages/QuizForm.vue:361 frontend/src/pages/QuizForm.vue:430 #: frontend/src/pages/ProgramForm.vue:248
#: frontend/src/pages/ProgramForm.vue:269
#: frontend/src/pages/ProgramForm.vue:295 frontend/src/pages/QuizForm.vue:343
#: frontend/src/pages/QuizForm.vue:362 frontend/src/pages/QuizForm.vue:431
msgid "Success" msgid "Success"
msgstr "" msgstr ""
@@ -4635,6 +4813,7 @@ msgstr ""
#: lms/lms/doctype/lms_live_class/lms_live_class.json #: lms/lms/doctype/lms_live_class/lms_live_class.json
#: lms/lms/doctype/lms_mentor_request/lms_mentor_request.json #: lms/lms/doctype/lms_mentor_request/lms_mentor_request.json
#: lms/lms/doctype/lms_payment/lms_payment.json #: lms/lms/doctype/lms_payment/lms_payment.json
#: lms/lms/doctype/lms_program/lms_program.json
#: lms/lms/doctype/lms_question/lms_question.json #: lms/lms/doctype/lms_question/lms_question.json
#: lms/lms/doctype/lms_quiz/lms_quiz.json #: lms/lms/doctype/lms_quiz/lms_quiz.json
#: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json #: lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json
@@ -4735,11 +4914,15 @@ msgstr ""
msgid "There are no chapters in this course. Create and manage chapters from here." msgid "There are no chapters in this course. Create and manage chapters from here."
msgstr "" msgstr ""
#: frontend/src/pages/Courses.vue:150 #: frontend/src/pages/Courses.vue:151
msgid "There are no courses available at the moment. Keep an eye out, fresh learning experiences are on the way soon!" msgid "There are no courses available at the moment. Keep an eye out, fresh learning experiences are on the way soon!"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:141 #: frontend/src/pages/Programs.vue:86
msgid "There are no programs available at the moment. Keep an eye out, fresh learning experiences are on the way soon!"
msgstr ""
#: lms/lms/doctype/lms_batch/lms_batch.py:146
msgid "There are no seats available in this batch." msgid "There are no seats available in this batch."
msgstr "" msgstr ""
@@ -4770,11 +4953,11 @@ msgstr ""
msgid "This course has:" msgid "This course has:"
msgstr "" msgstr ""
#: lms/lms/utils.py:1582 #: lms/lms/utils.py:1585
msgid "This course is free." msgid "This course is free."
msgstr "" msgstr ""
#: frontend/src/pages/SCORMChapter.vue:198 #: frontend/src/pages/SCORMChapter.vue:197
msgid "This is a chapter in the course {0}" msgid "This is a chapter in the course {0}"
msgstr "" msgstr ""
@@ -4866,6 +5049,7 @@ msgstr ""
#. Label of the title (Data) field in DocType 'LMS Course' #. Label of the title (Data) field in DocType 'LMS Course'
#. Label of the title (Data) field in DocType 'LMS Exercise' #. Label of the title (Data) field in DocType 'LMS Exercise'
#. Label of the title (Data) field in DocType 'LMS Live Class' #. Label of the title (Data) field in DocType 'LMS Live Class'
#. Label of the title (Data) field in DocType 'LMS Program'
#. Label of the title (Data) field in DocType 'LMS Quiz' #. Label of the title (Data) field in DocType 'LMS Quiz'
#. Label of the title (Data) field in DocType 'LMS Sidebar Item' #. Label of the title (Data) field in DocType 'LMS Sidebar Item'
#. Label of the title (Data) field in DocType 'LMS Timetable Template' #. Label of the title (Data) field in DocType 'LMS Timetable Template'
@@ -4873,7 +5057,8 @@ msgstr ""
#: frontend/src/components/Modals/DiscussionModal.vue:18 #: frontend/src/components/Modals/DiscussionModal.vue:18
#: frontend/src/components/Modals/LiveClassModal.vue:23 #: frontend/src/components/Modals/LiveClassModal.vue:23
#: frontend/src/pages/BatchForm.vue:20 frontend/src/pages/CourseForm.vue:32 #: frontend/src/pages/BatchForm.vue:20 frontend/src/pages/CourseForm.vue:32
#: frontend/src/pages/JobCreation.vue:20 frontend/src/pages/QuizForm.vue:48 #: frontend/src/pages/JobCreation.vue:20 frontend/src/pages/ProgramForm.vue:11
#: frontend/src/pages/Programs.vue:107 frontend/src/pages/QuizForm.vue:48
#: frontend/src/pages/Quizzes.vue:114 lms/lms/doctype/cohort/cohort.json #: frontend/src/pages/Quizzes.vue:114 lms/lms/doctype/cohort/cohort.json
#: lms/lms/doctype/cohort_subgroup/cohort_subgroup.json #: lms/lms/doctype/cohort_subgroup/cohort_subgroup.json
#: lms/lms/doctype/cohort_web_page/cohort_web_page.json #: lms/lms/doctype/cohort_web_page/cohort_web_page.json
@@ -4886,6 +5071,7 @@ msgstr ""
#: lms/lms/doctype/lms_course/lms_course.json #: lms/lms/doctype/lms_course/lms_course.json
#: lms/lms/doctype/lms_exercise/lms_exercise.json #: lms/lms/doctype/lms_exercise/lms_exercise.json
#: lms/lms/doctype/lms_live_class/lms_live_class.json #: lms/lms/doctype/lms_live_class/lms_live_class.json
#: lms/lms/doctype/lms_program/lms_program.json
#: lms/lms/doctype/lms_quiz/lms_quiz.json #: lms/lms/doctype/lms_quiz/lms_quiz.json
#: lms/lms/doctype/lms_sidebar_item/lms_sidebar_item.json #: lms/lms/doctype/lms_sidebar_item/lms_sidebar_item.json
#: lms/lms/doctype/lms_timetable_template/lms_timetable_template.json #: lms/lms/doctype/lms_timetable_template/lms_timetable_template.json
@@ -4894,7 +5080,7 @@ msgstr ""
msgid "Title" msgid "Title"
msgstr "" msgstr ""
#: frontend/src/components/Modals/ChapterModal.vue:169 #: frontend/src/components/Modals/ChapterModal.vue:174
msgid "Title is required" msgid "Title is required"
msgstr "" msgstr ""
@@ -4909,7 +5095,7 @@ msgstr ""
msgid "To Date" msgid "To Date"
msgstr "" msgstr ""
#: lms/lms/utils.py:1593 #: lms/lms/utils.py:1596
msgid "To join this batch, please contact the Administrator." msgid "To join this batch, please contact the Administrator."
msgstr "" msgstr ""
@@ -4973,7 +5159,7 @@ msgstr ""
msgid "Type" msgid "Type"
msgstr "" msgstr ""
#: frontend/src/components/Quiz.vue:580 #: frontend/src/components/Quiz.vue:583
msgid "Type your answer" msgid "Type your answer"
msgstr "" msgstr ""
@@ -5257,7 +5443,7 @@ msgstr ""
msgid "You are not enrolled in this course. Please enroll to access this lesson." msgid "You are not enrolled in this course. Please enroll to access this lesson."
msgstr "" msgstr ""
#: frontend/src/pages/Courses.vue:134 #: frontend/src/pages/Courses.vue:135
msgid "You can add chapters and lessons to it." msgid "You can add chapters and lessons to it."
msgstr "" msgstr ""
@@ -5429,6 +5615,10 @@ msgstr ""
msgid "jane@example.com" msgid "jane@example.com"
msgstr "" msgstr ""
#: frontend/src/pages/Programs.vue:32
msgid "members"
msgstr ""
#: lms/templates/quiz/quiz.html:106 #: lms/templates/quiz/quiz.html:106
msgid "of" msgid "of"
msgstr "" msgstr ""
@@ -5441,7 +5631,7 @@ msgstr ""
msgid "posted by" msgid "posted by"
msgstr "" msgstr ""
#: frontend/src/pages/QuizForm.vue:389 #: frontend/src/pages/QuizForm.vue:390
msgid "question_detail" msgid "question_detail"
msgstr "" msgstr ""
@@ -5473,7 +5663,7 @@ msgstr ""
msgid "{0} has submitted the assignment {1}" msgid "{0} has submitted the assignment {1}"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_enrollment/lms_enrollment.py:53 #: lms/lms/doctype/lms_enrollment/lms_enrollment.py:57
msgid "{0} is already a Student of {1} course through {2} batch" msgid "{0} is already a Student of {1} course through {2} batch"
msgstr "" msgstr ""
@@ -5481,7 +5671,7 @@ msgstr ""
msgid "{0} is already a mentor for course {1}" msgid "{0} is already a mentor for course {1}"
msgstr "" msgstr ""
#: lms/lms/doctype/lms_enrollment/lms_enrollment.py:26 #: lms/lms/doctype/lms_enrollment/lms_enrollment.py:30
msgid "{0} is already a {1} of the course {2}" msgid "{0} is already a {1} of the course {2}"
msgstr "" msgstr ""

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n" "Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: jannat@frappe.io\n" "Report-Msgid-Bugs-To: jannat@frappe.io\n"
"POT-Creation-Date: 2024-11-15 16:04+0000\n" "POT-Creation-Date: 2024-11-15 16:04+0000\n"
"PO-Revision-Date: 2024-11-18 17:31\n" "PO-Revision-Date: 2024-11-24 19:19\n"
"Last-Translator: jannat@frappe.io\n" "Last-Translator: jannat@frappe.io\n"
"Language-Team: Swedish\n" "Language-Team: Swedish\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@@ -78,7 +78,7 @@ msgstr "Godkännande av Villkor och/eller Principer"
#. Option for the 'Status' (Select) field in DocType 'Cohort Join Request' #. Option for the 'Status' (Select) field in DocType 'Cohort Join Request'
#: lms/lms/doctype/cohort_join_request/cohort_join_request.json #: lms/lms/doctype/cohort_join_request/cohort_join_request.json
msgid "Accepted" msgid "Accepted"
msgstr "Godkänd" msgstr "Accepterad"
#. Label of the account_id (Data) field in DocType 'Zoom Settings' #. Label of the account_id (Data) field in DocType 'Zoom Settings'
#: lms/lms/doctype/zoom_settings/zoom_settings.json #: lms/lms/doctype/zoom_settings/zoom_settings.json

File diff suppressed because it is too large Load Diff

View File

@@ -93,4 +93,5 @@ lms.patches.v2_0.sidebar_settings
lms.patches.v2_0.delete_certificate_request_notification #18-09-2024 lms.patches.v2_0.delete_certificate_request_notification #18-09-2024
lms.patches.v2_0.add_course_statistics #21-10-2024 lms.patches.v2_0.add_course_statistics #21-10-2024
lms.patches.v2_0.give_discussions_permissions lms.patches.v2_0.give_discussions_permissions
lms.patches.v2_0.delete_web_forms lms.patches.v2_0.delete_web_forms
lms.patches.v2_0.update_desk_access_for_lms_roles

View File

@@ -0,0 +1,9 @@
import frappe
def execute():
roles = ["Course Creator", "Moderator", "Batch Evaluator", "LMS Student"]
for role in roles:
if frappe.db.exists("Role", role):
frappe.db.set_value("Role", role, "desk_access", 0)