Compare commits

..

1 Commits

Author SHA1 Message Date
frappe-pr-bot
7fac29e3e4 chore: update POT file 2024-10-25 10:37:03 +00:00
54 changed files with 5179 additions and 68734 deletions

View File

@@ -13,6 +13,6 @@ module.exports = defineConfig({
openMode: 0,
},
e2e: {
baseUrl: "http://test:8000",
baseUrl: "http://test_site_ui:8000",
},
});

View File

@@ -5,7 +5,7 @@ describe("Course Creation", () => {
cy.visit("/lms/courses");
// Create a course
cy.get("header").children().last().children().last().click();
cy.get("a").contains("New").click();
cy.wait(1000);
cy.url().should("include", "/courses/new/edit");
@@ -73,7 +73,7 @@ describe("Course Creation", () => {
.should("be.visible")
.within(() => {
cy.get("label").contains("Title").type("Test Chapter");
cy.button("Create").click();
cy.button("Add Chapter").click();
});
// Add Lesson

View File

@@ -23,7 +23,7 @@
"codemirror-editor-vue3": "^2.8.0",
"dayjs": "^1.11.6",
"feather-icons": "^4.28.0",
"frappe-ui": "^0.1.72",
"frappe-ui": "^0.1.69",
"lucide-vue-next": "^0.383.0",
"markdown-it": "^14.0.0",
"pinia": "^2.0.33",

View File

@@ -25,7 +25,7 @@
</div>
</template>
<script setup>
import { createResource, Avatar } from 'frappe-ui'
import { createListResource, Avatar } from 'frappe-ui'
import { timeAgo } from '@/utils'
const props = defineProps({
@@ -35,15 +35,24 @@ const props = defineProps({
},
})
const communications = createResource({
url: 'lms.lms.api.get_announcements',
makeParams(value) {
return {
batch: props.batch,
}
const communications = createListResource({
doctype: 'Communication',
fields: [
'subject',
'content',
'recipients',
'cc',
'communication_date',
'sender',
'sender_full_name',
],
filters: {
reference_doctype: 'LMS Batch',
reference_name: props.batch,
},
orderBy: 'communication_date desc',
auto: true,
cache: ['announcement', props.batch],
cache: ['batch', props.batch],
})
</script>
<style>

View File

@@ -2,7 +2,6 @@
<div>
<label class="block mb-1" :class="labelClasses" v-if="label">
{{ label }}
<span class="text-red-500" v-if="required">*</span>
</label>
<div class="grid grid-cols-3 gap-1">
<Button
@@ -116,9 +115,6 @@ const props = defineProps({
type: Function,
default: (value) => `${value} is an Invalid value`,
},
required: {
type: Boolean,
},
})
const values = defineModel()

View File

@@ -30,29 +30,29 @@
</div>
<div class="flex flex-col flex-auto p-4">
<div class="flex items-center justify-between mb-2">
<div v-if="course.lessons">
<div v-if="course.lesson_count">
<Tooltip :text="__('Lessons')">
<span class="flex items-center">
<BookOpen class="h-4 w-4 stroke-1.5 text-gray-700 mr-1" />
{{ course.lessons }}
{{ course.lesson_count }}
</span>
</Tooltip>
</div>
<div v-if="course.enrollments">
<div v-if="course.enrollment_count">
<Tooltip :text="__('Enrolled Students')">
<span class="flex items-center">
<Users class="h-4 w-4 stroke-1.5 text-gray-700 mr-1" />
{{ course.enrollments }}
{{ course.enrollment_count }}
</span>
</Tooltip>
</div>
<div v-if="course.rating">
<div v-if="course.avg_rating">
<Tooltip :text="__('Average Rating')">
<span class="flex items-center">
<Star class="h-4 w-4 stroke-1.5 text-gray-700 mr-1" />
{{ course.rating }}
{{ course.avg_rating }}
</span>
</Tooltip>
</div>

View File

@@ -93,19 +93,21 @@
<div class="flex items-center mb-3">
<BookOpen class="h-5 w-5 stroke-1.5 text-gray-600" />
<span class="ml-2">
{{ course.data.lessons }} {{ __('Lessons') }}
{{ course.data.lesson_count }} {{ __('Lessons') }}
</span>
</div>
<div class="flex items-center mb-3">
<Users class="h-5 w-5 stroke-1.5 text-gray-600" />
<span class="ml-2">
{{ formatAmount(course.data.enrollments) }}
{{ course.data.enrollment_count_formatted }}
{{ __('Enrolled Students') }}
</span>
</div>
<div class="flex items-center">
<Star class="h-5 w-5 stroke-1.5 fill-orange-500 text-gray-50" />
<span class="ml-2"> {{ course.data.rating }} {{ __('Rating') }} </span>
<span class="ml-2">
{{ course.data.avg_rating }} {{ __('Rating') }}
</span>
</div>
</div>
</div>
@@ -114,7 +116,7 @@
import { BookOpen, Users, Star } from 'lucide-vue-next'
import { computed, inject } from 'vue'
import { Button, createResource } from 'frappe-ui'
import { showToast, formatAmount } from '@/utils/'
import { showToast } from '@/utils/'
import { capture } from '@/telemetry'
import { useRouter } from 'vue-router'

View File

@@ -76,7 +76,7 @@ const props = defineProps({
required: true,
},
avg_rating: {
type: String,
type: Number,
required: true,
},
membership: {

View File

@@ -21,7 +21,7 @@
<div class="space-y-2">
<div
class="flex text-sm font-medium space-x-2 cursor-pointer"
class="flex items-center text-sm font-medium space-x-2 cursor-pointer"
@click="openHelpDialog('upload')"
>
<span class="leading-5">
@@ -56,21 +56,6 @@
}}
</div>
</div>
<div class="space-y-2">
<div class="flex items-center text-sm font-medium space-x-2">
<span>
{{ __('What does include in preview mean?') }}
</span>
</div>
<div class="text-xs text-gray-600 mb-1 leading-5">
{{
__(
'If Include in Preview is enabled for a lesson then the lesson will also be accessible to non logged in users.'
)
}}
</div>
</div>
</div>
<ExplanationVideos v-model="showExplanation" :type="type" />
</template>

View File

@@ -48,7 +48,7 @@
<a
:href="cls.join_url"
target="_blank"
class="w-full cursor-pointer inline-flex items-center justify-center gap-2 transition-colors focus:outline-none text-gray-800 bg-gray-100 hover:bg-gray-200 active:bg-gray-300 focus-visible:ring focus-visible:ring-gray-400 h-7 text-base px-2 rounded"
class="w-1/2 cursor-pointer inline-flex items-center justify-center gap-2 transition-colors focus:outline-none text-gray-800 bg-gray-100 hover:bg-gray-200 active:bg-gray-300 focus-visible:ring focus-visible:ring-gray-400 h-7 text-base px-2 rounded"
>
<Video class="h-4 w-4 stroke-1.5" />
{{ __('Join') }}

View File

@@ -44,7 +44,7 @@
<script setup>
import { Dialog, Input, TextEditor, createResource } from 'frappe-ui'
import { reactive } from 'vue'
import { showToast } from '@/utils/'
import { createToast } from '@/utils/'
const show = defineModel()
@@ -94,14 +94,22 @@ const makeAnnouncement = (close) => {
},
onSuccess() {
close()
showToast(
__('Success'),
__('Announcement has been sent successfully'),
'check'
)
createToast({
title: 'Success',
text: 'Announcement has been sent successfully',
icon: 'Check',
iconClasses: 'bg-green-600 text-white rounded-md p-px',
})
},
onError(err) {
showToast(__('Error'), __(err.messages?.[0] || err), 'check')
createToast({
title: 'Error',
text: err.messages?.[0] || err,
icon: 'x',
iconClasses: 'bg-red-600 text-white rounded-md p-px',
position: 'top-center',
timeout: 10,
})
},
}
)

View File

@@ -2,11 +2,11 @@
<Dialog
v-model="show"
:options="{
title: chapterDetail ? __('Edit Chapter') : __('Add Chapter'),
title: __('Add Chapter'),
size: 'lg',
actions: [
{
label: chapterDetail ? __('Edit') : __('Create'),
label: chapterDetail ? __('Edit Chapter') : __('Add Chapter'),
variant: 'solid',
onClick: (close) =>
chapterDetail ? editChapter(close) : addChapter(close),

View File

@@ -1,7 +1,7 @@
<template>
<div v-if="quiz.data">
<div
class="bg-blue-100 space-y-1 py-2 px-2 mb-4 rounded-md text-sm text-blue-800"
class="bg-blue-100 space-y-1 py-2 px-2 rounded-md text-sm text-blue-800"
>
<div class="leading-5">
{{

View File

@@ -236,7 +236,7 @@ const breadcrumbs = computed(() => {
const isStudent = computed(() => {
return (
user?.data &&
batch.data?.students?.length &&
batch.data?.students.length &&
batch.data?.students.includes(user.data.name)
)
})

View File

@@ -32,65 +32,57 @@
</div>
</div>
<div class="mb-4">
<div class="text-xs text-gray-600 mb-2">
{{ __('Meta Image') }}
</div>
<FileUploader
v-if="!batch.image"
:fileTypes="['image/*']"
:validateFile="validateFile"
@success="(file) => saveImage(file)"
>
<template v-slot="{ file, progress, uploading, openFileSelector }">
<div class="flex items-center">
<div class="border rounded-md w-fit py-5 px-20">
<Image class="size-5 stroke-1 text-gray-700" />
</div>
<div class="ml-4">
<Button @click="openFileSelector">
{{ __('Upload') }}
<div>
<FileUploader
v-if="!batch.image"
class="mt-4"
:fileTypes="['image/*']"
:validateFile="validateFile"
@success="(file) => saveImage(file)"
>
<template v-slot="{ file, progress, uploading, openFileSelector }">
<div class="mb-4">
<Button @click="openFileSelector" :loading="uploading">
{{ uploading ? `Uploading ${progress}%` : 'Upload an image' }}
</Button>
<div class="mt-2 text-gray-600 text-sm">
{{
__(
'Appears when the batch URL is shared on any online platform'
)
}}
</div>
</div>
</template>
</FileUploader>
<div v-else class="mb-4">
<div class="text-xs text-gray-600 mb-1">
{{ __('Meta Image') }}
</div>
</template>
</FileUploader>
<div v-else class="mb-4">
<div class="flex items-center">
<img :src="batch.image.file_url" class="border rounded-md w-40" />
<div class="ml-4">
<Button @click="removeImage()">
{{ __('Remove') }}
</Button>
<div class="mt-2 text-gray-600 text-sm">
{{
__(
'Appears when the batch URL is shared on any online platform'
)
}}
<div class="flex items-center">
<div class="border rounded-md p-2 mr-2">
<FileText class="h-5 w-5 stroke-1.5 text-gray-700" />
</div>
<div class="flex flex-col">
<span>
{{ batch.image.file_name }}
</span>
<span class="text-sm text-gray-500 mt-1">
{{ getFileSize(batch.image.file_size) }}
</span>
</div>
<X
@click="removeImage()"
class="bg-gray-200 rounded-md cursor-pointer stroke-1.5 w-5 h-5 p-1 ml-4"
/>
</div>
</div>
</div>
<MultiSelect
v-model="instructors"
doctype="User"
:label="__('Instructors')"
/>
</div>
<MultiSelect
v-model="instructors"
doctype="User"
:label="__('Instructors')"
/>
<div class="mb-4">
<FormControl
v-model="batch.description"
:label="__('Description')"
type="textarea"
class="my-4"
:placeholder="__('Short description of the batch')"
/>
<div>
<label class="block text-sm text-gray-600 mb-1">
@@ -141,7 +133,6 @@
v-model="batch.timezone"
:label="__('Timezone')"
type="text"
:placeholder="__('Example: IST (+5:30)')"
class="mb-4"
/>
</div>
@@ -158,7 +149,6 @@
:label="__('Seat Count')"
type="number"
class="mb-4"
:placeholder="__('Number of seats available')"
/>
<FormControl
v-model="batch.evaluation_end_date"
@@ -238,11 +228,11 @@ import {
createResource,
} from 'frappe-ui'
import Link from '@/components/Controls/Link.vue'
import { useRouter } from 'vue-router'
import { showToast } from '../utils'
import { Image } from 'lucide-vue-next'
import { capture } from '@/telemetry'
import MultiSelect from '@/components/Controls/MultiSelect.vue'
import { useRouter } from 'vue-router'
import { getFileSize, showToast } from '../utils'
import { X, FileText } from 'lucide-vue-next'
import { capture } from '@/telemetry'
const router = useRouter()
const user = inject('$user')

View File

@@ -40,7 +40,6 @@
{{ __('Loading Batches...') }}
</div>
<Tabs
v-if="hasBatches"
v-model="tabIndex"
:tabs="makeTabs"
tablistClass="overflow-x-visible flex-wrap !gap-3 md:flex-nowrap"
@@ -80,63 +79,24 @@
<BatchCard :batch="batch" />
</router-link>
</div>
<div v-else class="p-5 italic text-gray-500">
{{ __('No {0} batches').format(tab.label.toLowerCase()) }}
<div
v-else
class="grid flex-1 place-items-center text-xl font-medium text-gray-500"
>
<div class="flex flex-col items-center justify-center mt-4">
<div>
{{ __('No {0} batches found').format(tab.label.toLowerCase()) }}
</div>
</div>
</div>
</template>
</Tabs>
<div
v-else-if="
!batches.loading &&
!hasBatches &&
(user.data?.is_instructor || user.data?.is_moderator)
"
class="grid grid-cols-3 p-5"
>
<router-link
:to="{
name: 'BatchForm',
params: {
batchName: 'new',
},
}"
>
<div class="bg-gray-50 py-32 px-5 rounded-md">
<div class="flex flex-col items-center text-center space-y-2">
<Plus
class="size-10 stroke-1 text-gray-800 p-1 rounded-full border bg-white"
/>
<div class="font-medium">
{{ __('Create a Batch') }}
</div>
<span class="text-gray-700 text-sm leading-4">
{{ __('You can link courses and assessments to it.') }}
</span>
</div>
</div>
</router-link>
</div>
<div
v-else-if="!batches.loading && !hasBatches"
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 batches found') }}
</div>
<div>
{{
__(
'There are no batches available at the moment. Keep an eye out, fresh learning experiences are on the way soon!'
)
}}
</div>
</div>
</div>
</div>
</template>
<script setup>
import {
createListResource,
createResource,
Breadcrumbs,
Button,
@@ -144,14 +104,13 @@ import {
Badge,
Select,
} from 'frappe-ui'
import { BookOpen, Plus } from 'lucide-vue-next'
import { Plus } from 'lucide-vue-next'
import BatchCard from '@/components/BatchCard.vue'
import { inject, ref, computed, onMounted, watch } from 'vue'
import { updateDocumentTitle } from '@/utils'
const user = inject('$user')
const currentCategory = ref(null)
const hasBatches = ref(false)
onMounted(() => {
let queries = new URLSearchParams(location.search)
@@ -160,10 +119,10 @@ onMounted(() => {
}
})
const batches = createResource({
const batches = createListResource({
doctype: 'LMS Batch',
url: 'lms.lms.utils.get_batches',
cache: ['batches', user.data?.email],
cache: ['batches', user?.data?.email],
auto: true,
})
@@ -224,14 +183,6 @@ const addToTabs = (label) => {
})
}
watch(batches, () => {
Object.keys(batches.data).forEach((key) => {
if (batches.data[key].length) {
hasBatches.value = true
}
})
})
watch(
() => currentCategory.value,
() => {

View File

@@ -16,16 +16,16 @@
</div>
<div class="flex items-center">
<Tooltip
v-if="course.data.rating"
v-if="course.data.avg_rating"
:text="__('Average Rating')"
class="flex items-center"
>
<Star class="h-5 w-5 text-gray-100 fill-orange-500" />
<span class="ml-1">
{{ course.data.rating }}
{{ course.data.avg_rating }}
</span>
</Tooltip>
<span v-if="course.data.rating" class="mx-3">&middot;</span>
<span v-if="course.data.avg_rating" class="mx-3">&middot;</span>
<Tooltip
v-if="course.data.enrollment_count"
:text="__('Enrolled Students')"
@@ -74,7 +74,7 @@
</div>
<CourseReviews
:courseName="course.data.name"
:avg_rating="course.data.rating"
:avg_rating="course.data.avg_rating"
:membership="course.data.membership"
/>
</div>
@@ -116,7 +116,7 @@ const breadcrumbs = computed(() => {
let items = [{ label: 'All Courses', route: { name: 'Courses' } }]
items.push({
label: course?.data?.title,
route: { name: 'CourseDetail', params: { courseName: course?.data?.name } },
route: { name: 'CourseDetail', params: { course: course?.data?.name } },
})
return items
})

View File

@@ -23,23 +23,15 @@
v-model="course.title"
:label="__('Title')"
class="mb-4"
:required="true"
/>
<FormControl
v-model="course.short_introduction"
:label="__('Short Introduction')"
:placeholder="
__(
'A one line introduction to the course that appears on the course card'
)
"
class="mb-4"
:required="true"
/>
<div class="mb-4">
<div class="mb-1.5 text-sm text-gray-600">
<div class="mb-1.5 text-sm text-gray-700">
{{ __('Course Description') }}
<span class="text-red-500">*</span>
</div>
<TextEditor
:content="course.description"
@@ -49,62 +41,49 @@
editorClass="prose-sm max-w-none border-b border-x bg-gray-100 rounded-b-md py-1 px-2 min-h-[7rem]"
/>
</div>
<div class="mb-4">
<div class="text-xs text-gray-600 mb-2">
{{ __('Course Image') }}
<span class="text-red-500">*</span>
</div>
<FileUploader
v-if="!course.course_image"
:fileTypes="['image/*']"
:validateFile="validateFile"
@success="(file) => saveImage(file)"
<FileUploader
v-if="!course.course_image"
:fileTypes="['image/*']"
:validateFile="validateFile"
@success="(file) => saveImage(file)"
>
<template
v-slot="{ file, progress, uploading, openFileSelector }"
>
<template
v-slot="{ file, progress, uploading, openFileSelector }"
>
<div class="flex items-center">
<div class="border rounded-md w-fit py-5 px-20">
<Image class="size-5 stroke-1 text-gray-700" />
</div>
<div class="ml-4">
<Button @click="openFileSelector">
{{ __('Upload') }}
</Button>
<div class="mt-2 text-gray-600 text-sm">
{{
__('Appears on the course card in the course list')
}}
</div>
</div>
</div>
</template>
</FileUploader>
<div v-else class="mb-4">
<div class="flex items-center">
<img
:src="course.course_image.file_url"
class="border rounded-md w-40"
/>
<div class="ml-4">
<Button @click="removeImage()">
{{ __('Remove') }}
</Button>
<div class="mt-2 text-gray-600 text-sm">
{{ __('Appears on the course card in the course list') }}
</div>
</div>
<div class="mb-4">
<Button @click="openFileSelector" :loading="uploading">
{{
uploading ? `Uploading ${progress}%` : 'Upload an image'
}}
</Button>
</div>
</template>
</FileUploader>
<div v-else class="mb-4">
<div class="text-xs text-gray-600 mb-1">
{{ __('Course Image') }}
</div>
<div class="flex items-center">
<div class="border rounded-md p-2 mr-2">
<FileText class="h-5 w-5 stroke-1.5 text-gray-700" />
</div>
<div class="flex flex-col">
<span>
{{ course.course_image.file_name }}
</span>
<span class="text-sm text-gray-500 mt-1">
{{ getFileSize(course.course_image.file_size) }}
</span>
</div>
<X
@click="removeImage()"
class="bg-gray-200 rounded-md cursor-pointer stroke-1.5 w-5 h-5 p-1 ml-4"
/>
</div>
</div>
<FormControl
v-model="course.video_link"
:label="__('Preview Video')"
:placeholder="
__(
'Paste the youtube link of a short video introducing the course'
)
"
class="mb-4"
/>
<div class="mb-4">
@@ -125,8 +104,6 @@
</div>
<FormControl
v-model="newTag"
:placeholder="__('Keywords for the course')"
class="w-52"
@keyup.enter="updateTags()"
id="tags"
/>
@@ -144,7 +121,6 @@
v-model="instructors"
doctype="User"
:label="__('Instructors')"
:required="true"
/>
</div>
<div class="container border-t">
@@ -154,7 +130,7 @@
<div class="grid grid-cols-3 gap-10 mb-4">
<div
v-if="user.data?.is_moderator"
class="flex flex-col space-y-4"
class="flex flex-col space-y-3"
>
<FormControl
type="checkbox"
@@ -248,9 +224,14 @@ import {
reactive,
watch,
} from 'vue'
import { convertToTitleCase, showToast, updateDocumentTitle } from '@/utils'
import {
convertToTitleCase,
showToast,
getFileSize,
updateDocumentTitle,
} from '@/utils'
import Link from '@/components/Controls/Link.vue'
import { FileText, Image, X } from 'lucide-vue-next'
import { FileText, X } from 'lucide-vue-next'
import { useRouter } from 'vue-router'
import CourseOutline from '@/components/CourseOutline.vue'
import MultiSelect from '@/components/Controls/MultiSelect.vue'

View File

@@ -8,7 +8,7 @@
:items="[{ label: __('Courses'), route: { name: 'Courses' } }]"
/>
<div class="flex space-x-2 justify-end">
<div class="w-40 md:w-44">
<div class="w-46 md:w-44">
<FormControl
v-if="categories.data?.length"
type="select"
@@ -48,7 +48,6 @@
</header>
<div class="">
<Tabs
v-if="hasCourses"
v-model="tabIndex"
tablistClass="overflow-x-visible flex-wrap !gap-3 md:flex-nowrap"
:tabs="makeTabs"
@@ -102,57 +101,18 @@
<CourseCard :course="course" />
</router-link>
</div>
<div v-else class="p-5 italic text-gray-500">
{{ __('No {0} courses').format(tab.label.toLowerCase()) }}
<div
v-else
class="grid flex-1 place-items-center text-xl font-medium text-gray-500"
>
<div class="flex flex-col items-center justify-center mt-4">
<div>
{{ __('No {0} courses found').format(tab.label.toLowerCase()) }}
</div>
</div>
</div>
</template>
</Tabs>
<div
v-else-if="
!courses.loading &&
(user.data?.is_moderator || user.data?.is_instructor)
"
class="grid grid-cols-3 p-5"
>
<router-link
:to="{
name: 'CourseForm',
params: {
courseName: 'new',
},
}"
>
<div class="bg-gray-50 py-32 px-5 rounded-md">
<div class="flex flex-col items-center text-center space-y-2">
<Plus
class="size-10 stroke-1 text-gray-800 p-1 rounded-full border bg-white"
/>
<div class="font-medium">
{{ __('Create a Course') }}
</div>
<span class="text-gray-700 text-sm leading-4">
{{ __('You can add chapters and lessons to it.') }}
</span>
</div>
</div>
</router-link>
</div>
<div
v-else-if="!courses.loading && !hasCourses"
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 courses found') }}
</div>
<div>
{{
__(
'There are no courses available at the moment. Keep an eye out, fresh learning experiences are on the way soon!'
)
}}
</div>
</div>
</div>
</div>
</template>
@@ -167,14 +127,13 @@ import {
createResource,
} from 'frappe-ui'
import CourseCard from '@/components/CourseCard.vue'
import { BookOpen, Plus, Search } from 'lucide-vue-next'
import { Plus, Search } from 'lucide-vue-next'
import { ref, computed, inject, onMounted, watch } from 'vue'
import { updateDocumentTitle } from '@/utils'
const user = inject('$user')
const searchQuery = ref('')
const currentCategory = ref(null)
const hasCourses = ref(false)
onMounted(() => {
let queries = new URLSearchParams(location.search)
@@ -264,16 +223,6 @@ const categories = createResource({
},
})
watch(courses, () => {
if (courses.data) {
Object.keys(courses.data).forEach((section) => {
if (courses.data[section].length) {
hasCourses.value = true
}
})
}
})
watch(
() => currentCategory.value,
() => {

View File

@@ -17,9 +17,14 @@
)
}}
</p>
<Button v-if="user.data" @click="enrollStudent()" variant="solid">
{{ __('Start Learning') }}
</Button>
<router-link
v-if="user.data"
:to="{ name: 'CourseDetail', params: { courseName: courseName } }"
>
<Button variant="solid">
{{ __('Start Learning') }}
</Button>
</router-link>
<Button v-else @click="redirectToLogin()">
{{ __('Login') }}
</Button>
@@ -189,7 +194,7 @@ import { createResource, Breadcrumbs, Button } from 'frappe-ui'
import { computed, watch, inject, ref, onMounted, onBeforeUnmount } from 'vue'
import CourseOutline from '@/components/CourseOutline.vue'
import UserAvatar from '@/components/UserAvatar.vue'
import { useRouter, useRoute } from 'vue-router'
import { useRoute } from 'vue-router'
import { ChevronLeft, ChevronRight } from 'lucide-vue-next'
import Discussions from '@/components/Discussions.vue'
import { getEditorTools, updateDocumentTitle } from '../utils'
@@ -199,7 +204,6 @@ import CourseInstructors from '@/components/CourseInstructors.vue'
import ProgressBar from '@/components/ProgressBar.vue'
const user = inject('$user')
const router = useRouter()
const route = useRoute()
const allowDiscussions = ref(false)
const editor = ref(null)
@@ -297,14 +301,14 @@ const breadcrumbs = computed(() => {
let items = [{ label: 'All Courses', route: { name: 'Courses' } }]
items.push({
label: lesson?.data?.course_title,
route: { name: 'CourseDetail', params: { courseName: props.courseName } },
route: { name: 'CourseDetail', params: { course: props.courseName } },
})
items.push({
label: lesson?.data?.title,
route: {
name: 'Lesson',
params: {
courseName: props.courseName,
course: props.courseName,
chapterNumber: props.chapterNumber,
lessonNumber: props.lessonNumber,
},
@@ -375,30 +379,6 @@ const allowInstructorContent = () => {
return false
}
const enrollment = createResource({
url: 'frappe.client.insert',
makeParams() {
return {
doc: {
doctype: 'LMS Enrollment',
course: props.courseName,
member: user.data?.name,
},
}
},
})
const enrollStudent = () => {
enrollment.submit(
{},
{
onSuccess() {
window.location.reload()
},
}
)
}
const redirectToLogin = () => {
window.location.href = `/login?redirect-to=/lms/courses/${props.courseName}`
}

View File

@@ -69,7 +69,7 @@
</div>
</template>
<script setup>
import { Breadcrumbs, Button, createResource, FormControl } from 'frappe-ui'
import { Breadcrumbs, FormControl, createResource, Button } from 'frappe-ui'
import {
computed,
reactive,

View File

@@ -57,15 +57,6 @@ export function formatNumberIntoCurrency(number, currency) {
return ''
}
// create a function that formats numbers in thousands to k
export function formatAmount(amount) {
if (amount > 999) {
return (amount / 1000).toFixed(1) + 'k'
}
return amount
}
export function convertToTitleCase(str) {
if (!str) {
return ''

View File

@@ -51,7 +51,7 @@ export class Quiz {
app.mount(this.wrapper)
return
}
this.wrapper.innerHTML = `<div class='border rounded-md p-10 text-center bg-gray-50 mb-2'>
this.wrapper.innerHTML = `<div class='border rounded-md p-10 text-center mb-2'>
<span class="font-medium">
Quiz: ${quiz}
</span>

View File

@@ -1224,10 +1224,10 @@ fraction.js@^4.3.7:
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7"
integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==
frappe-ui@^0.1.72:
version "0.1.72"
resolved "https://registry.yarnpkg.com/frappe-ui/-/frappe-ui-0.1.72.tgz#f5550056ddee7ad4341f2c1825d046404d221820"
integrity sha512-XWYKmCjw3ViD+/+tZMUiYqwHFlMGMsVuazOYiN5bKlE+aiheJsnHlOOUyQswYX1Y7jNxuC7gGpSLNg2ZpXA7hA==
frappe-ui@^0.1.69:
version "0.1.69"
resolved "https://registry.yarnpkg.com/frappe-ui/-/frappe-ui-0.1.69.tgz#bfc6d19dff97d2666c36da63f5de62f819539406"
integrity sha512-MKHYTcRvmccZwTYlIcmf4OCbJQH5eqKXsq3Cj2lbnmoWuuTh9m7T3AoRKEwOIlZ0mSGCH9yzaF2BINBXGpIJdQ==
dependencies:
"@headlessui/vue" "^1.7.14"
"@popperjs/core" "^2.11.2"

View File

@@ -1 +1 @@
__version__ = "2.10.0"
__version__ = "2.9.0"

View File

@@ -110,8 +110,7 @@ doc_events = {
# ---------------
scheduler_events = {
"hourly": [
"lms.lms.doctype.lms_certificate_request.lms_certificate_request.schedule_evals",
"lms.lms.api.update_course_statistics",
"lms.lms.doctype.lms_certificate_request.lms_certificate_request.schedule_evals"
],
"daily": ["lms.job.doctype.job_opportunity.job_opportunity.update_job_openings"],
}

View File

@@ -6,9 +6,8 @@ from frappe.translate import get_all_translations
from frappe import _
from frappe.query_builder import DocType
from frappe.query_builder.functions import Count
from frappe.utils import time_diff, now_datetime, get_datetime, flt
from frappe.utils import time_diff, now_datetime, get_datetime
from typing import Optional
from lms.lms.utils import get_average_rating, get_lesson_count
@frappe.whitelist()
@@ -761,44 +760,3 @@ def get_payment_gateway_details(payment_gateway):
"doctype": doctype,
"docname": docname,
}
def update_course_statistics():
courses = frappe.get_all("LMS Course", fields=["name"])
for course in courses:
lessons = get_lesson_count(course.name)
enrollments = frappe.db.count(
"LMS Enrollment", {"course": course.name, "member_type": "Student"}
)
avg_rating = get_average_rating(course.name) or 0
avg_rating = flt(avg_rating, frappe.get_system_settings("float_precision") or 3)
frappe.db.set_value(
"LMS Course",
course.name,
{"lessons": lessons, "enrollments": enrollments, "rating": avg_rating},
)
@frappe.whitelist()
def get_announcements(batch):
return frappe.get_all(
"Communication",
filters={
"reference_doctype": "LMS Batch",
"reference_name": batch,
},
fields=[
"subject",
"content",
"recipients",
"cc",
"communication_date",
"sender",
"sender_full_name",
],
order_by="communication_date desc",
)

View File

@@ -7,3 +7,17 @@ from frappe.model.document import Document
class BatchStudent(Document):
pass
@frappe.whitelist()
def enroll_batch(batch_name):
if frappe.db.exists(
"Batch Student", {"student": frappe.session.user, "parent": batch_name}
):
frappe.throw("You are already enrolled in this batch")
enrollment = frappe.new_doc("Batch Student")
enrollment.student = frappe.session.user
enrollment.parent = batch_name
enrollment.parentfield = "students"
enrollment.parenttype = "LMS Batch"
enrollment.save(ignore_permissions=True)

View File

@@ -9,8 +9,9 @@
"engine": "InnoDB",
"field_order": [
"course",
"column_break_3",
"title",
"column_break_3",
"description",
"section_break_5",
"lessons"
],
@@ -34,6 +35,11 @@
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"fieldname": "description",
"fieldtype": "Small Text",
"label": "Description"
},
{
"fieldname": "section_break_5",
"fieldtype": "Section Break"
@@ -53,7 +59,7 @@
"link_fieldname": "chapter"
}
],
"modified": "2024-10-29 16:54:20.904683",
"modified": "2023-09-29 17:03:58.013819",
"modified_by": "Administrator",
"module": "LMS",
"name": "Course Chapter",

View File

@@ -33,7 +33,6 @@ class LMSBatch(Document):
self.validate_timetable()
self.send_confirmation_mail()
self.validate_evaluation_end_date()
self.add_students_to_live_class()
def validate_batch_end_date(self):
if self.end_date < self.start_date:
@@ -140,27 +139,6 @@ class LMSBatch(Document):
if cint(self.seat_count) < len(self.students):
frappe.throw(_("There are no seats available in this batch."))
def add_students_to_live_class(self):
for student in self.students:
if student.is_new():
live_classes = frappe.get_all(
"LMS Live Class", {"batch_name": self.name}, ["name", "event"]
)
for live_class in live_classes:
if live_class.event:
frappe.get_doc(
{
"doctype": "Event Participants",
"reference_doctype": "User",
"reference_docname": student.student,
"email": student.student,
"parent": live_class.event,
"parenttype": "Event",
"parentfield": "event_participants",
}
).save()
def validate_timetable(self):
for schedule in self.timetable:
if schedule.start_time and schedule.end_time:

View File

@@ -48,12 +48,7 @@
"certification_section",
"enable_certification",
"column_break_rxww",
"expiry",
"tab_4_tab",
"statistics_section",
"enrollments",
"lessons",
"rating"
"expiry"
],
"fields": [
{
@@ -254,36 +249,6 @@
"fieldtype": "Link",
"label": "Category",
"options": "LMS Category"
},
{
"fieldname": "tab_4_tab",
"fieldtype": "Tab Break",
"label": "Statistics"
},
{
"fieldname": "statistics_section",
"fieldtype": "Section Break"
},
{
"default": "0",
"fieldname": "enrollments",
"fieldtype": "Data",
"label": "Enrollments",
"read_only": 1
},
{
"default": "0",
"fieldname": "lessons",
"fieldtype": "Data",
"label": "Lessons",
"read_only": 1
},
{
"default": "0",
"fieldname": "rating",
"fieldtype": "Data",
"label": "Rating",
"read_only": 1
}
],
"is_published_field": "published",
@@ -310,7 +275,7 @@
}
],
"make_attachments_public": 1,
"modified": "2024-10-30 23:08:31.842860",
"modified": "2024-09-21 10:23:58.633912",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Course",

View File

@@ -187,3 +187,192 @@ def reindex_exercises(doc):
course = frappe.get_doc("LMS Course", course_data["name"])
course.reindex_exercises()
frappe.msgprint("All exercises in this course have been re-indexed.")
@frappe.whitelist(allow_guest=True)
def search_course(text):
courses = frappe.get_all(
"LMS Course",
filters={"published": True},
or_filters={
"title": ["like", f"%{text}%"],
"tags": ["like", f"%{text}%"],
"short_introduction": ["like", f"%{text}%"],
"description": ["like", f"%{text}%"],
},
fields=["name", "title"],
)
return courses
@frappe.whitelist()
def submit_for_review(course):
chapters = frappe.get_all("Chapter Reference", {"parent": course})
if not len(chapters):
return "No Chp"
frappe.db.set_value("LMS Course", course, "status", "Under Review")
return "OK"
@frappe.whitelist()
def save_course(
tags,
title,
short_introduction,
video_link,
description,
course,
published,
upcoming,
image=None,
paid_course=False,
course_price=None,
currency=None,
):
if not can_create_courses(course):
return
if course:
doc = frappe.get_doc("LMS Course", course)
else:
doc = frappe.get_doc({"doctype": "LMS Course"})
doc.update(
{
"title": title,
"short_introduction": short_introduction,
"video_link": video_link,
"image": image,
"description": description,
"tags": tags,
"published": cint(published),
"upcoming": cint(upcoming),
"paid_course": cint(paid_course),
"course_price": course_price,
"currency": currency,
}
)
doc.save(ignore_permissions=True)
return doc.name
@frappe.whitelist()
def save_chapter(course, title, chapter_description, idx, chapter):
if chapter:
doc = frappe.get_doc("Course Chapter", chapter)
else:
doc = frappe.get_doc({"doctype": "Course Chapter"})
doc.update({"course": course, "title": title, "description": chapter_description})
doc.save(ignore_permissions=True)
if chapter:
chapter_reference = frappe.get_doc("Chapter Reference", {"chapter": chapter})
else:
chapter_reference = frappe.get_doc(
{
"doctype": "Chapter Reference",
"parent": course,
"parenttype": "LMS Course",
"parentfield": "chapters",
"idx": idx,
}
)
chapter_reference.update({"chapter": doc.name})
chapter_reference.save(ignore_permissions=True)
return doc.name
@frappe.whitelist()
def save_lesson(
title,
body,
chapter,
preview,
idx,
lesson,
instructor_notes=None,
youtube=None,
quiz_id=None,
question=None,
file_type=None,
):
if lesson:
doc = frappe.get_doc("Course Lesson", lesson)
else:
doc = frappe.get_doc({"doctype": "Course Lesson"})
doc.update(
{
"chapter": chapter,
"title": title,
"body": body,
"instructor_notes": instructor_notes,
"include_in_preview": preview,
"youtube": youtube,
"quiz_id": quiz_id,
"question": question,
"file_type": file_type,
}
)
doc.save(ignore_permissions=True)
if lesson:
lesson_reference = frappe.get_doc("Lesson Reference", {"lesson": lesson})
else:
lesson_reference = frappe.get_doc(
{
"doctype": "Lesson Reference",
"parent": chapter,
"parenttype": "Course Chapter",
"parentfield": "lessons",
"idx": idx,
}
)
lesson_reference.update({"lesson": doc.name})
lesson_reference.save(ignore_permissions=True)
return doc.name
@frappe.whitelist()
def reorder_lesson(old_chapter, old_lesson_array, new_chapter, new_lesson_array):
if old_chapter == new_chapter:
sort_lessons(new_chapter, new_lesson_array)
else:
sort_lessons(old_chapter, old_lesson_array)
sort_lessons(new_chapter, new_lesson_array)
def sort_lessons(chapter, lesson_array):
lesson_array = json.loads(lesson_array)
for les in lesson_array:
ref = frappe.get_all("Lesson Reference", {"lesson": les}, ["name", "idx"])
if ref:
frappe.db.set_value(
"Lesson Reference",
ref[0].name,
{
"parent": chapter,
"idx": lesson_array.index(les) + 1,
},
)
@frappe.whitelist()
def reorder_chapter(chapter_array):
chapter_array = json.loads(chapter_array)
for chap in chapter_array:
ref = frappe.get_all("Chapter Reference", {"chapter": chap}, ["name", "idx"])
if ref:
frappe.db.set_value(
"Chapter Reference",
ref[0].name,
{
"idx": chapter_array.index(chap) + 1,
},
)

View File

@@ -75,8 +75,7 @@
"in_standard_filter": 1,
"label": "Course",
"options": "LMS Course",
"reqd": 1,
"search_index": 1
"reqd": 1
},
{
"fieldname": "current_lesson",
@@ -127,7 +126,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-10-30 12:44:16.103598",
"modified": "2024-05-14 14:50:08.405033",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Enrollment",

View File

@@ -10,20 +10,19 @@
"title",
"host",
"batch_name",
"event",
"column_break_astv",
"description",
"section_break_glxh",
"date",
"duration",
"column_break_spvt",
"time",
"duration",
"section_break_glxh",
"description",
"column_break_spvt",
"timezone",
"section_break_yrpq",
"password",
"auto_recording",
"section_break_yrpq",
"start_url",
"column_break_yokr",
"auto_recording",
"join_url"
],
"fields": [
@@ -123,18 +122,11 @@
"fieldtype": "Select",
"label": "Auto Recording",
"options": "No Recording\nLocal\nCloud"
},
{
"fieldname": "event",
"fieldtype": "Link",
"label": "Event",
"options": "Event",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-10-31 15:41:35.540856",
"modified": "2024-01-09 11:22:33.272341",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Live Class",

View File

@@ -16,7 +16,6 @@ class LMSLiveClass(Document):
if calendar:
event = self.create_event()
self.add_event_participants(event, calendar)
frappe.db.set_value(self.doctype, self.name, "event", event.name)
def create_event(self):
start = f"{self.date} {self.time}"

View File

@@ -76,7 +76,6 @@
"default": "0",
"fieldname": "payment_received",
"fieldtype": "Check",
"in_standard_filter": 1,
"label": "Payment Received"
},
{
@@ -141,7 +140,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-10-31 15:33:39.420366",
"modified": "2023-10-26 16:54:12.408274",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Payment",

View File

@@ -86,32 +86,32 @@ def get_charts(data):
completed = 0
less_than_hundred = 0
less_than_seventy_one = 0
less_than_forty_one = 0
less_than_eleven = 0
less_than_seventy = 0
less_than_forty = 0
less_than_ten = 0
for row in data:
if row.progress == 100:
completed += 1
elif row.progress < 100 and row.progress > 70:
less_than_hundred += 1
elif row.progress < 71 and row.progress > 40:
less_than_seventy_one += 1
elif row.progress < 41 and row.progress > 10:
less_than_forty_one += 1
elif row.progress < 11:
less_than_eleven += 1
elif row.progress < 70 and row.progress > 40:
less_than_seventy += 1
elif row.progress < 40 and row.progress > 10:
less_than_forty += 1
elif row.progress < 10:
less_than_ten += 1
charts = {
"data": {
"labels": ["0-10", "11-40", "41-70", "71-99", "100"],
"labels": ["0-10", "10-40", "40-70", "70-99", "100"],
"datasets": [
{
"name": "Progress (%)",
"values": [
less_than_eleven,
less_than_forty_one,
less_than_seventy_one,
less_than_ten,
less_than_forty,
less_than_seventy,
less_than_hundred,
completed,
],

View File

@@ -109,7 +109,7 @@ def get_chapters(course):
chapter_details = frappe.db.get_value(
"Course Chapter",
{"name": chapter.chapter},
["name", "title"],
["name", "title", "description"],
as_dict=True,
)
chapter.update(chapter_details)
@@ -157,12 +157,11 @@ def get_lesson_details(chapter, progress=False):
"file_type",
"instructor_notes",
"course",
"content",
],
as_dict=True,
)
lesson_details.number = f"{chapter.idx}.{row.idx}"
lesson_details.icon = get_lesson_icon(lesson_details.body, lesson_details.content)
lesson_details.icon = get_lesson_icon(lesson_details.body)
if progress:
lesson_details.is_complete = get_progress(lesson_details.course, lesson_details.name)
@@ -171,38 +170,20 @@ def get_lesson_details(chapter, progress=False):
return lessons
def get_lesson_icon(body, content):
if content:
content = json.loads(content)
def get_lesson_icon(content):
icon = None
macros = find_macros(content)
for block in content.get("blocks"):
if block.get("type") == "upload" and block.get("data").get("file_type").lower() in [
"mp4",
"webm",
"ogg",
"mov",
]:
return "icon-youtube"
if block.get("type") == "embed" and block.get("data").get("service") in [
"youtube",
"vimeo",
]:
return "icon-youtube"
if block.get("type") == "quiz":
return "icon-quiz"
return "icon-list"
macros = find_macros(body)
for macro in macros:
if macro[0] == "YouTubeVideo" or macro[0] == "Video":
return "icon-youtube"
icon = "icon-youtube"
elif macro[0] == "Quiz":
return "icon-quiz"
icon = "icon-quiz"
return "icon-list"
if not icon:
icon = "icon-list"
return icon
@frappe.whitelist(allow_guest=True)
@@ -1046,13 +1027,23 @@ def get_course_details(course):
"currency",
"amount_usd",
"enable_certification",
"lessons",
"enrollments",
"rating",
],
as_dict=1,
)
course_details.tags = course_details.tags.split(",") if course_details.tags else []
course_details.lesson_count = get_lesson_count(course_details.name)
course_details.enrollment_count = frappe.db.count(
"LMS Enrollment", {"course": course_details.name, "member_type": "Student"}
)
course_details.enrollment_count_formatted = format_number(
course_details.enrollment_count
)
avg_rating = get_average_rating(course_details.name) or 0
course_details.avg_rating = flt(
avg_rating, frappe.get_system_settings("float_precision") or 3
)
course_details.instructors = get_instructors(course_details.name)
if course_details.paid_course:
@@ -1101,14 +1092,14 @@ def get_categorized_courses(courses):
):
new.append(course)
if course.membership:
if course.membership and course.published:
enrolled.append(course)
elif course.is_instructor:
created.append(course)
categories = [live, enrolled, created]
for category in categories:
category.sort(key=lambda x: x.enrollments, reverse=True)
category.sort(key=lambda x: x.enrollment_count, reverse=True)
live.sort(key=lambda x: x.featured, reverse=True)
@@ -1133,7 +1124,7 @@ def get_course_outline(course, progress=False):
chapter_details = frappe.db.get_value(
"Course Chapter",
chapter.chapter,
["name", "title"],
["name", "title", "description"],
as_dict=True,
)
chapter_details["idx"] = chapter.idx

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Frappe LMS VERSION\n"
"Report-Msgid-Bugs-To: jannat@frappe.io\n"
"POT-Creation-Date: 2024-11-01 16:04+0000\n"
"PO-Revision-Date: 2024-11-01 16:04+0000\n"
"POT-Creation-Date: 2024-10-25 10:37+0000\n"
"PO-Revision-Date: 2024-10-25 10:37+0000\n"
"Last-Translator: jannat@frappe.io\n"
"Language-Team: jannat@frappe.io\n"
"MIME-Version: 1.0\n"
@@ -60,10 +60,6 @@ msgstr ""
msgid "<span style=\"font-size: 18px;\"><b>Statistics</b></span>"
msgstr ""
#: frontend/src/pages/CourseForm.vue:32
msgid "A one line introduction to the course that appears on the course card"
msgstr ""
#: frontend/src/pages/ProfileAbout.vue:4
msgid "About"
msgstr ""
@@ -104,6 +100,7 @@ msgstr ""
#: frontend/src/components/CourseOutline.vue:11
#: frontend/src/components/CreateOutline.vue:18
#: frontend/src/components/Modals/ChapterModal.vue:5
#: frontend/src/components/Modals/ChapterModal.vue:9
msgid "Add Chapter"
msgstr ""
@@ -226,7 +223,7 @@ msgstr ""
#. Label of the amount (Currency) field in DocType 'Web Form'
#. Label of the amount (Currency) field in DocType 'LMS Batch'
#. Label of the amount (Currency) field in DocType 'LMS Payment'
#: frontend/src/pages/BatchForm.vue:208 lms/fixtures/custom_field.json
#: frontend/src/pages/BatchForm.vue:198 lms/fixtures/custom_field.json
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/lms/doctype/lms_payment/lms_payment.json
#: lms/public/js/common_functions.js:379
@@ -270,14 +267,6 @@ msgstr ""
msgid "Answer"
msgstr ""
#: frontend/src/pages/CourseForm.vue:76 frontend/src/pages/CourseForm.vue:94
msgid "Appears on the course card in the course list"
msgstr ""
#: frontend/src/pages/BatchForm.vue:55 frontend/src/pages/BatchForm.vue:73
msgid "Appears when the batch URL is shared on any online platform"
msgstr ""
#: frontend/src/pages/JobDetail.vue:131
msgid "Applications Received"
msgstr ""
@@ -476,7 +465,7 @@ msgid "Batch Description"
msgstr ""
#. Label of the batch_details (Text Editor) field in DocType 'LMS Batch'
#: frontend/src/pages/BatchForm.vue:97 lms/lms/doctype/lms_batch/lms_batch.json
#: frontend/src/pages/BatchForm.vue:89 lms/lms/doctype/lms_batch/lms_batch.json
#: lms/public/js/common_functions.js:349
#: lms/templates/emails/batch_confirmation.html:30
msgid "Batch Details"
@@ -643,8 +632,8 @@ msgstr ""
#. Label of the category (Link) field in DocType 'LMS Batch'
#. Label of the category (Data) field in DocType 'LMS Category'
#. Label of the category (Link) field in DocType 'LMS Course'
#: frontend/src/pages/BatchForm.vue:189 frontend/src/pages/Batches.vue:16
#: frontend/src/pages/CourseForm.vue:139 frontend/src/pages/Courses.vue:17
#: frontend/src/pages/BatchForm.vue:179 frontend/src/pages/Batches.vue:16
#: frontend/src/pages/CourseForm.vue:116 frontend/src/pages/Courses.vue:17
#: frontend/src/pages/JobDetail.vue:102
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/lms/doctype/lms_category/lms_category.json
@@ -945,7 +934,7 @@ msgstr ""
msgid "Completed"
msgstr ""
#: frontend/src/pages/CourseForm.vue:192
#: frontend/src/pages/CourseForm.vue:168
msgid "Completion Certificate"
msgstr ""
@@ -995,7 +984,7 @@ msgstr ""
msgid "Contract"
msgstr ""
#: lms/lms/utils.py:442
#: lms/lms/utils.py:423
msgid "Cookie Policy"
msgstr ""
@@ -1116,7 +1105,7 @@ msgstr ""
msgid "Course Data"
msgstr ""
#: frontend/src/pages/CourseForm.vue:41
#: frontend/src/pages/CourseForm.vue:34
msgid "Course Description"
msgstr ""
@@ -1125,7 +1114,7 @@ msgstr ""
msgid "Course Evaluator"
msgstr ""
#: frontend/src/pages/CourseForm.vue:54
#: frontend/src/pages/CourseForm.vue:64
msgid "Course Image"
msgstr ""
@@ -1148,7 +1137,7 @@ msgid "Course Name"
msgstr ""
#. Label of the course_price (Currency) field in DocType 'LMS Course'
#: frontend/src/pages/CourseForm.vue:210
#: frontend/src/pages/CourseForm.vue:186
#: lms/lms/doctype/lms_course/lms_course.json
msgid "Course Price"
msgstr ""
@@ -1181,7 +1170,7 @@ msgstr ""
msgid "Course already added to the batch."
msgstr ""
#: frontend/src/pages/CourseForm.vue:457
#: frontend/src/pages/CourseForm.vue:433
msgid "Course price and currency are mandatory for paid courses"
msgstr ""
@@ -1219,10 +1208,6 @@ msgstr ""
msgid "Cover Image"
msgstr ""
#: frontend/src/components/Modals/ChapterModal.vue:9
msgid "Create"
msgstr ""
#: lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.js:7
msgid "Create LMS Certificate"
msgstr ""
@@ -1231,11 +1216,7 @@ msgstr ""
msgid "Create LMS Certificate Evaluation"
msgstr ""
#: frontend/src/pages/Batches.vue:110
msgid "Create a Batch"
msgstr ""
#: frontend/src/pages/Courses.vue:131 lms/templates/onboarding_header.html:19
#: lms/templates/onboarding_header.html:19
msgid "Create a Course"
msgstr ""
@@ -1251,7 +1232,7 @@ msgstr ""
#. Label of the currency (Link) field in DocType 'LMS Batch'
#. Label of the currency (Link) field in DocType 'LMS Course'
#. Label of the currency (Link) field in DocType 'LMS Payment'
#: frontend/src/pages/BatchForm.vue:216 frontend/src/pages/CourseForm.vue:217
#: frontend/src/pages/BatchForm.vue:206 frontend/src/pages/CourseForm.vue:193
#: lms/fixtures/custom_field.json lms/lms/doctype/lms_batch/lms_batch.json
#: lms/lms/doctype/lms_course/lms_course.json
#: lms/lms/doctype/lms_payment/lms_payment.json
@@ -1309,7 +1290,7 @@ msgstr ""
#. Label of the section_break_glxh (Section Break) field in DocType 'LMS Live
#. Class'
#: frontend/src/pages/BatchForm.vue:110
#: frontend/src/pages/BatchForm.vue:102
#: lms/lms/doctype/lms_live_class/lms_live_class.json
msgid "Date and Time"
msgstr ""
@@ -1357,6 +1338,7 @@ msgstr ""
#. Label of the description (Markdown Editor) field in DocType 'Cohort'
#. Label of the description (Markdown Editor) field in DocType 'Cohort
#. Subgroup'
#. Label of the description (Small Text) field in DocType 'Course Chapter'
#. Label of the description (Small Text) field in DocType 'LMS Badge'
#. Label of the description (Small Text) field in DocType 'LMS Batch'
#. Label of the description (Markdown Editor) field in DocType 'LMS Batch Old'
@@ -1365,11 +1347,12 @@ msgstr ""
#. Label of the description (Text) field in DocType 'LMS Live Class'
#. Label of the description (Small Text) field in DocType 'Work Experience'
#: frontend/src/components/Modals/LiveClassModal.vue:73
#: frontend/src/pages/BatchForm.vue:90 frontend/src/pages/JobCreation.vue:43
#: frontend/src/pages/BatchForm.vue:83 frontend/src/pages/JobCreation.vue:43
#: lms/job/doctype/job_opportunity/job_opportunity.json
#: lms/lms/doctype/certification/certification.json
#: lms/lms/doctype/cohort/cohort.json
#: lms/lms/doctype/cohort_subgroup/cohort_subgroup.json
#: lms/lms/doctype/course_chapter/course_chapter.json
#: lms/lms/doctype/lms_badge/lms_badge.json
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/lms/doctype/lms_batch_old/lms_batch_old.json
@@ -1391,7 +1374,7 @@ msgstr ""
msgid "Details"
msgstr ""
#: frontend/src/pages/CourseForm.vue:187
#: frontend/src/pages/CourseForm.vue:163
msgid "Disable Self Enrollment"
msgstr ""
@@ -1466,14 +1449,13 @@ msgstr ""
#: frontend/src/components/BatchOverlay.vue:93
#: frontend/src/components/CourseCardOverlay.vue:86
#: frontend/src/components/Modals/ChapterModal.vue:9
#: frontend/src/pages/JobDetail.vue:31 frontend/src/pages/Lesson.vue:70
#: frontend/src/pages/Profile.vue:32
msgid "Edit"
msgstr ""
#: frontend/src/components/CourseOutline.vue:106
#: frontend/src/components/Modals/ChapterModal.vue:5
#: frontend/src/components/Modals/ChapterModal.vue:9
msgid "Edit Chapter"
msgstr ""
@@ -1549,7 +1531,7 @@ msgstr ""
#. Label of the end_date (Date) field in DocType 'Cohort'
#. Label of the end_date (Date) field in DocType 'LMS Batch'
#: frontend/src/pages/BatchForm.vue:122 lms/lms/doctype/cohort/cohort.json
#: frontend/src/pages/BatchForm.vue:114 lms/lms/doctype/cohort/cohort.json
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/public/js/common_functions.js:282
msgid "End Date"
@@ -1567,7 +1549,7 @@ msgstr ""
#. Label of the end_time (Time) field in DocType 'LMS Certificate Evaluation'
#. Label of the end_time (Time) field in DocType 'LMS Certificate Request'
#. Label of the end_time (Time) field in DocType 'Scheduled Flow'
#: frontend/src/pages/BatchForm.vue:136
#: frontend/src/pages/BatchForm.vue:128
#: frontend/src/pages/ProfileEvaluator.vue:18
#: lms/lms/doctype/evaluator_schedule/evaluator_schedule.json
#: lms/lms/doctype/lms_batch/lms_batch.json
@@ -1603,15 +1585,13 @@ msgstr ""
msgid "Enrollment Count"
msgstr ""
#: lms/lms/utils.py:1692
#: lms/lms/utils.py:1683
msgid "Enrollment Failed"
msgstr ""
#. Label of the enrollments (Data) field in DocType 'LMS Course'
#. Label of a chart in the LMS Workspace
#. Label of a shortcut in the LMS Workspace
#: frontend/src/pages/Statistics.vue:45
#: lms/lms/doctype/lms_course/lms_course.json lms/lms/workspace/lms/lms.json
#: frontend/src/pages/Statistics.vue:45 lms/lms/workspace/lms/lms.json
msgid "Enrollments"
msgstr ""
@@ -1653,7 +1633,7 @@ msgid "Evaluation Details"
msgstr ""
#. Label of the evaluation_end_date (Date) field in DocType 'LMS Batch'
#: frontend/src/pages/BatchForm.vue:165
#: frontend/src/pages/BatchForm.vue:155
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/public/js/common_functions.js:333
msgid "Evaluation End Date"
@@ -1715,10 +1695,6 @@ msgstr ""
msgid "Event"
msgstr ""
#: frontend/src/pages/BatchForm.vue:144
msgid "Example: IST (+5:30)"
msgstr ""
#. Label of the exercise (Link) field in DocType 'Exercise Latest Submission'
#. Label of the exercise (Link) field in DocType 'Exercise Submission'
#: lms/lms/doctype/exercise_latest_submission/exercise_latest_submission.json
@@ -1789,7 +1765,7 @@ msgstr ""
#. Label of the featured (Check) field in DocType 'LMS Course'
#: frontend/src/components/CourseCard.vue:16
#: frontend/src/pages/CourseForm.vue:180
#: frontend/src/pages/CourseForm.vue:156
#: lms/lms/doctype/lms_course/lms_course.json
msgid "Featured"
msgstr ""
@@ -2052,10 +2028,6 @@ msgstr ""
msgid "Icon"
msgstr ""
#: frontend/src/components/LessonHelp.vue:68
msgid "If Include in Preview is enabled for a lesson then the lesson will also be accessible to non logged in users."
msgstr ""
#: lms/templates/emails/mentor_request_creation_email.html:5
msgid "If you are not any more interested to mentor the course"
msgstr ""
@@ -2192,7 +2164,7 @@ msgstr ""
#. Label of the instructors (Table MultiSelect) field in DocType 'LMS Batch'
#. Label of the instructors (Table MultiSelect) field in DocType 'LMS Course'
#: frontend/src/pages/BatchForm.vue:85 frontend/src/pages/CourseForm.vue:146
#: frontend/src/pages/BatchForm.vue:77 frontend/src/pages/CourseForm.vue:123
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/lms/doctype/lms_course/lms_course.json
msgid "Instructors"
@@ -2351,10 +2323,6 @@ msgstr ""
msgid "Join URL"
msgstr ""
#: frontend/src/pages/CourseForm.vue:128
msgid "Keywords for the course"
msgstr ""
#. Name of a Workspace
#: lms/lms/workspace/lms/lms.json
msgid "LMS"
@@ -2608,11 +2576,9 @@ msgstr ""
#. Label of the lessons (Table) field in DocType 'Course Chapter'
#. Group in Course Chapter's connections
#. Label of the lessons (Data) field in DocType 'LMS Course'
#: frontend/src/components/CourseCard.vue:34
#: frontend/src/components/CourseCardOverlay.vue:96
#: lms/lms/doctype/course_chapter/course_chapter.json
#: lms/lms/doctype/lms_course/lms_course.json
msgid "Lessons"
msgstr ""
@@ -2785,7 +2751,7 @@ msgid "Maximun Attempts"
msgstr ""
#. Label of the medium (Select) field in DocType 'LMS Batch'
#: frontend/src/pages/BatchForm.vue:184
#: frontend/src/pages/BatchForm.vue:174
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/public/js/common_functions.js:309
msgid "Medium"
@@ -2933,7 +2899,7 @@ msgid "Mentors"
msgstr ""
#. Label of the meta_image (Attach Image) field in DocType 'LMS Batch'
#: frontend/src/pages/BatchForm.vue:36 lms/lms/doctype/lms_batch/lms_batch.json
#: frontend/src/pages/BatchForm.vue:53 lms/lms/doctype/lms_batch/lms_batch.json
#: lms/public/js/common_functions.js:362
msgid "Meta Image"
msgstr ""
@@ -2969,11 +2935,11 @@ msgstr ""
msgid "Modified By"
msgstr ""
#: lms/lms/api.py:191
#: lms/lms/api.py:190
msgid "Module Name is incorrect or does not exist."
msgstr ""
#: lms/lms/api.py:187
#: lms/lms/api.py:186
msgid "Module is incorrect."
msgstr ""
@@ -3040,11 +3006,11 @@ msgstr ""
msgid "New Sign Up"
msgstr ""
#: lms/lms/utils.py:632
#: lms/lms/utils.py:613
msgid "New comment in batch {0}"
msgstr ""
#: lms/lms/utils.py:625
#: lms/lms/utils.py:606
msgid "New reply on the topic {0} in course {1}"
msgstr ""
@@ -3082,10 +3048,6 @@ msgstr ""
msgid "No announcements"
msgstr ""
#: frontend/src/pages/Batches.vue:125
msgid "No batches found"
msgstr ""
#: lms/templates/certificates_section.html:23
msgid "No certificates"
msgstr ""
@@ -3094,10 +3056,6 @@ msgstr ""
msgid "No courses created"
msgstr ""
#: frontend/src/pages/Courses.vue:146
msgid "No courses found"
msgstr ""
#: lms/templates/courses_under_review.html:14
msgid "No courses under review"
msgstr ""
@@ -3126,12 +3084,12 @@ msgstr ""
msgid "No {0}"
msgstr ""
#: frontend/src/pages/Batches.vue:84
msgid "No {0} batches"
#: frontend/src/pages/Batches.vue:88
msgid "No {0} batches found"
msgstr ""
#: frontend/src/pages/Courses.vue:106
msgid "No {0} courses"
#: frontend/src/pages/Courses.vue:110
msgid "No {0} courses found"
msgstr ""
#: lms/templates/quiz/quiz.html:147
@@ -3186,10 +3144,6 @@ msgstr ""
msgid "Notify me when available"
msgstr ""
#: frontend/src/pages/BatchForm.vue:161
msgid "Number of seats available"
msgstr ""
#. Label of the sb_00 (Section Break) field in DocType 'Zoom Settings'
#: lms/lms/doctype/zoom_settings/zoom_settings.json
msgid "OAuth Client ID"
@@ -3222,7 +3176,7 @@ msgstr ""
msgid "Only files of type {0} will be accepted."
msgstr ""
#: frontend/src/pages/CourseForm.vue:473 frontend/src/utils/index.js:518
#: frontend/src/pages/CourseForm.vue:449 frontend/src/utils/index.js:509
msgid "Only image file is allowed."
msgstr ""
@@ -3330,14 +3284,14 @@ msgid "Pages"
msgstr ""
#. Label of the paid_batch (Check) field in DocType 'LMS Batch'
#: frontend/src/pages/BatchForm.vue:204
#: frontend/src/pages/BatchForm.vue:194
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/public/js/common_functions.js:373
msgid "Paid Batch"
msgstr ""
#. Label of the paid_course (Check) field in DocType 'LMS Course'
#: frontend/src/pages/CourseForm.vue:205
#: frontend/src/pages/CourseForm.vue:181
#: lms/lms/doctype/lms_course/lms_course.json
msgid "Paid Course"
msgstr ""
@@ -3379,13 +3333,9 @@ msgstr ""
msgid "Password"
msgstr ""
#: frontend/src/pages/CourseForm.vue:104
msgid "Paste the youtube link of a short video introducing the course"
msgstr ""
#. Label of the payment (Link) field in DocType 'Batch Student'
#. Label of the payment (Link) field in DocType 'LMS Enrollment'
#: frontend/src/pages/BatchForm.vue:198
#: frontend/src/pages/BatchForm.vue:188
#: lms/lms/doctype/batch_student/batch_student.json
#: lms/lms/doctype/lms_enrollment/lms_enrollment.json
msgid "Payment"
@@ -3477,7 +3427,7 @@ msgstr ""
msgid "Phone Number"
msgstr ""
#: frontend/src/components/CourseCardOverlay.vue:141
#: frontend/src/components/CourseCardOverlay.vue:143
msgid "Please Login"
msgstr ""
@@ -3538,7 +3488,7 @@ msgstr ""
msgid "Please login to access this page."
msgstr ""
#: lms/lms/api.py:183
#: lms/lms/api.py:182
msgid "Please login to continue with payment."
msgstr ""
@@ -3628,7 +3578,7 @@ msgstr ""
msgid "Preview Image"
msgstr ""
#: frontend/src/pages/CourseForm.vue:102
#: frontend/src/pages/CourseForm.vue:86
msgid "Preview Video"
msgstr ""
@@ -3638,7 +3588,7 @@ msgstr ""
#. Label of the pricing_tab (Tab Break) field in DocType 'LMS Batch'
#. Label of the pricing_tab (Tab Break) field in DocType 'LMS Course'
#: frontend/src/pages/CourseForm.vue:199
#: frontend/src/pages/CourseForm.vue:175
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/lms/doctype/lms_course/lms_course.json
#: lms/public/js/common_functions.js:368
@@ -3656,7 +3606,7 @@ msgstr ""
msgid "Primary Subgroup"
msgstr ""
#: lms/lms/utils.py:441
#: lms/lms/utils.py:422
msgid "Privacy Policy"
msgstr ""
@@ -3708,7 +3658,7 @@ msgstr ""
#. Label of the published (Check) field in DocType 'LMS Batch'
#. Label of the published (Check) field in DocType 'LMS Course'
#: frontend/src/components/Modals/Event.vue:108
#: frontend/src/pages/BatchForm.vue:24 frontend/src/pages/CourseForm.vue:162
#: frontend/src/pages/BatchForm.vue:24 frontend/src/pages/CourseForm.vue:138
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/lms/doctype/lms_course/lms_course.json
#: lms/public/js/common_functions.js:266
@@ -3721,7 +3671,7 @@ msgid "Published Courses"
msgstr ""
#. Label of the published_on (Date) field in DocType 'LMS Course'
#: frontend/src/pages/CourseForm.vue:166
#: frontend/src/pages/CourseForm.vue:142
#: lms/lms/doctype/lms_course/lms_course.json
msgid "Published On"
msgstr ""
@@ -3842,13 +3792,11 @@ msgid "Quizzes"
msgstr ""
#. Label of the rating (Rating) field in DocType 'LMS Certificate Evaluation'
#. Label of the rating (Data) field in DocType 'LMS Course'
#. Label of the rating (Rating) field in DocType 'LMS Course Review'
#: frontend/src/components/CourseCardOverlay.vue:108
#: frontend/src/components/CourseCardOverlay.vue:109
#: frontend/src/components/Modals/Event.vue:86
#: frontend/src/components/Modals/ReviewModal.vue:20
#: lms/lms/doctype/lms_certificate_evaluation/lms_certificate_evaluation.json
#: lms/lms/doctype/lms_course/lms_course.json
#: lms/lms/doctype/lms_course_review/lms_course_review.json
#: lms/templates/reviews.html:125
msgid "Rating"
@@ -3919,10 +3867,6 @@ msgstr ""
msgid "Related Courses"
msgstr ""
#: frontend/src/pages/BatchForm.vue:69 frontend/src/pages/CourseForm.vue:91
msgid "Remove"
msgstr ""
#: frontend/src/components/Modals/AnnouncementModal.vue:26
msgid "Reply To"
msgstr ""
@@ -4078,7 +4022,7 @@ msgid "Search for an icon"
msgstr ""
#. Label of the seat_count (Int) field in DocType 'LMS Batch'
#: frontend/src/pages/BatchForm.vue:158
#: frontend/src/pages/BatchForm.vue:149
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/public/js/common_functions.js:327
msgid "Seat Count"
@@ -4122,7 +4066,7 @@ msgid "Set your Password"
msgstr ""
#: frontend/src/components/Modals/Settings.vue:7
#: frontend/src/pages/BatchForm.vue:152 frontend/src/pages/CourseForm.vue:152
#: frontend/src/pages/BatchForm.vue:143 frontend/src/pages/CourseForm.vue:128
#: frontend/src/pages/ProfileRoles.vue:4 frontend/src/pages/QuizForm.vue:78
msgid "Settings"
msgstr ""
@@ -4132,15 +4076,11 @@ msgid "Share on"
msgstr ""
#. Label of the short_introduction (Small Text) field in DocType 'LMS Course'
#: frontend/src/pages/CourseForm.vue:30
#: frontend/src/pages/CourseForm.vue:29
#: lms/lms/doctype/lms_course/lms_course.json
msgid "Short Introduction"
msgstr ""
#: frontend/src/pages/BatchForm.vue:93
msgid "Short description of the batch"
msgstr ""
#. Label of the show_answer (Check) field in DocType 'LMS Assignment'
#: lms/lms/doctype/lms_assignment/lms_assignment.json
msgid "Show Answer"
@@ -4301,7 +4241,7 @@ msgstr ""
#. Label of the start_date (Date) field in DocType 'Education Detail'
#. Label of the start_date (Date) field in DocType 'LMS Batch'
#. Label of the start_date (Date) field in DocType 'LMS Batch Old'
#: frontend/src/pages/BatchForm.vue:116
#: frontend/src/pages/BatchForm.vue:108
#: lms/lms/doctype/education_detail/education_detail.json
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/lms/doctype/lms_batch_old/lms_batch_old.json
@@ -4322,7 +4262,7 @@ msgstr ""
#. Label of the start_time (Time) field in DocType 'LMS Certificate Evaluation'
#. Label of the start_time (Time) field in DocType 'LMS Certificate Request'
#. Label of the start_time (Time) field in DocType 'Scheduled Flow'
#: frontend/src/pages/BatchForm.vue:130
#: frontend/src/pages/BatchForm.vue:122
#: frontend/src/pages/ProfileEvaluator.vue:15
#: lms/lms/doctype/evaluator_schedule/evaluator_schedule.json
#: lms/lms/doctype/lms_batch/lms_batch.json
@@ -4361,9 +4301,7 @@ msgstr ""
msgid "State"
msgstr ""
#. Label of the tab_4_tab (Tab Break) field in DocType 'LMS Course'
#. Label of the statistics (Check) field in DocType 'LMS Settings'
#: lms/lms/doctype/lms_course/lms_course.json
#: lms/lms/doctype/lms_settings/lms_settings.json lms/www/lms.py:133
msgid "Statistics"
msgstr ""
@@ -4493,7 +4431,7 @@ msgstr ""
#: frontend/src/components/BatchCourses.vue:150
#: frontend/src/components/BatchOverlay.vue:135
#: frontend/src/components/BatchStudents.vue:157
#: frontend/src/components/CourseCardOverlay.vue:161
#: frontend/src/components/CourseCardOverlay.vue:163
#: frontend/src/components/Modals/AssessmentModal.vue:73
#: frontend/src/components/Modals/Event.vue:255
#: frontend/src/components/Modals/Event.vue:310
@@ -4567,7 +4505,7 @@ msgid "System Manager"
msgstr ""
#. Label of the tags (Data) field in DocType 'LMS Course'
#: frontend/src/pages/CourseForm.vue:112
#: frontend/src/pages/CourseForm.vue:91
#: lms/lms/doctype/lms_course/lms_course.json
msgid "Tags"
msgstr ""
@@ -4595,7 +4533,7 @@ msgstr ""
msgid "Temporarily Disabled"
msgstr ""
#: lms/lms/utils.py:440
#: lms/lms/utils.py:421
msgid "Terms of Use"
msgstr ""
@@ -4647,18 +4585,10 @@ msgstr ""
msgid "The status of your application has changed."
msgstr ""
#: frontend/src/pages/Batches.vue:129
msgid "There are no batches available at the moment. Keep an eye out, fresh learning experiences are on the way soon!"
msgstr ""
#: frontend/src/components/CreateOutline.vue:12
msgid "There are no chapters in this course. Create and manage chapters from here."
msgstr ""
#: frontend/src/pages/Courses.vue:150
msgid "There are no courses 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:140
msgid "There are no seats available in this batch."
msgstr ""
@@ -4690,7 +4620,7 @@ msgstr ""
msgid "This course has:"
msgstr ""
#: lms/lms/utils.py:1572
#: lms/lms/utils.py:1563
msgid "This course is free."
msgstr ""
@@ -4759,7 +4689,7 @@ msgstr ""
#. Label of the timezone (Data) field in DocType 'LMS Certificate Request'
#. Label of the timezone (Data) field in DocType 'LMS Live Class'
#: frontend/src/components/Modals/LiveClassModal.vue:44
#: frontend/src/pages/BatchForm.vue:142
#: frontend/src/pages/BatchForm.vue:134
#: lms/lms/doctype/lms_batch/lms_batch.json
#: lms/lms/doctype/lms_certificate_request/lms_certificate_request.json
#: lms/lms/doctype/lms_live_class/lms_live_class.json
@@ -4825,7 +4755,7 @@ msgstr ""
msgid "To Date is mandatory in Work Experience."
msgstr ""
#: lms/lms/utils.py:1583
#: lms/lms/utils.py:1574
msgid "To join this batch, please contact the Administrator."
msgstr ""
@@ -4942,7 +4872,7 @@ msgstr ""
#. Option for the 'Status' (Select) field in DocType 'Cohort'
#. Label of the upcoming (Check) field in DocType 'LMS Course'
#: frontend/src/pages/CourseForm.vue:175 lms/lms/doctype/cohort/cohort.json
#: frontend/src/pages/CourseForm.vue:151 lms/lms/doctype/cohort/cohort.json
#: lms/lms/doctype/lms_course/lms_course.json
msgid "Upcoming"
msgstr ""
@@ -4966,10 +4896,6 @@ msgstr ""
msgid "Update Password"
msgstr ""
#: frontend/src/pages/BatchForm.vue:51 frontend/src/pages/CourseForm.vue:72
msgid "Upload"
msgstr ""
#: frontend/src/pages/AssignmentSubmission.vue:69
msgid "Upload File"
msgstr ""
@@ -5092,10 +5018,6 @@ msgstr ""
msgid "Welcome to {0}!"
msgstr ""
#: frontend/src/components/LessonHelp.vue:63
msgid "What does include in preview mean?"
msgstr ""
#: lms/templates/courses_under_review.html:15
msgid "When a course gets submitted for review, it will be listed here."
msgstr ""
@@ -5149,11 +5071,11 @@ msgstr ""
msgid "You already have an evaluation on {0} at {1} for the course {2}."
msgstr ""
#: lms/lms/api.py:207
#: lms/lms/api.py:206
msgid "You are already enrolled for this batch."
msgstr ""
#: lms/lms/api.py:199
#: lms/lms/api.py:198
msgid "You are already enrolled for this course."
msgstr ""
@@ -5165,10 +5087,6 @@ msgstr ""
msgid "You are not a mentor of the course {0}"
msgstr ""
#: frontend/src/pages/Courses.vue:134
msgid "You can add chapters and lessons to it."
msgstr ""
#: lms/templates/emails/lms_course_interest.html:13
#: lms/templates/emails/lms_invite_request_approved.html:11
msgid "You can also copy-paste following link in your browser"
@@ -5186,10 +5104,6 @@ msgstr ""
msgid "You can find their resume attached to this email."
msgstr ""
#: frontend/src/pages/Batches.vue:113
msgid "You can link courses and assessments to it."
msgstr ""
#: lms/lms/doctype/lms_certificate_request/lms_certificate_request.py:115
msgid "You cannot schedule evaluations after {0}."
msgstr ""
@@ -5231,7 +5145,7 @@ msgstr ""
msgid "You have been enrolled in this batch"
msgstr ""
#: frontend/src/components/CourseCardOverlay.vue:162
#: frontend/src/components/CourseCardOverlay.vue:164
msgid "You have been enrolled in this course"
msgstr ""
@@ -5243,7 +5157,7 @@ msgstr ""
msgid "You haven't enrolled for any courses"
msgstr ""
#: frontend/src/components/CourseCardOverlay.vue:142
#: frontend/src/components/CourseCardOverlay.vue:144
msgid "You need to login first to enroll for this course"
msgstr ""
@@ -5361,7 +5275,7 @@ msgstr ""
msgid "you can"
msgstr ""
#: lms/lms/api.py:732 lms/lms/api.py:740
#: lms/lms/api.py:731 lms/lms/api.py:739
msgid "{0} Settings not found"
msgstr ""
@@ -5397,7 +5311,7 @@ msgstr ""
msgid "{0} is your evaluator"
msgstr ""
#: lms/lms/utils.py:709
#: lms/lms/utils.py:690
msgid "{0} mentioned you in a comment"
msgstr ""
@@ -5405,11 +5319,11 @@ msgstr ""
msgid "{0} mentioned you in a comment in your batch."
msgstr ""
#: lms/lms/utils.py:662 lms/lms/utils.py:668
#: lms/lms/utils.py:643 lms/lms/utils.py:649
msgid "{0} mentioned you in a comment in {1}"
msgstr ""
#: lms/lms/utils.py:480
#: lms/lms/utils.py:461
msgid "{0}k"
msgstr ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -90,5 +90,4 @@ lms.patches.v1_0.set_published_on
lms.patches.v2_0.fix_progress_percentage
lms.patches.v2_0.add_discussion_topic_titles
lms.patches.v2_0.sidebar_settings
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.delete_certificate_request_notification #18-09-2024

View File

@@ -1,6 +0,0 @@
import frappe
from lms.lms.api import update_course_statistics
def execute():
update_course_statistics()