fix: misc issues
This commit is contained in:
@@ -1,7 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="text-lg font-semibold mb-4">
|
||||
{{ __('Assessments') }}
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="text-lg font-semibold mb-4">
|
||||
{{ __('Assessments') }}
|
||||
</div>
|
||||
<Button v-if="canSeeAddButton()" @click="showModal = true">
|
||||
<template #prefix>
|
||||
<Plus class="h-4 w-4" />
|
||||
</template>
|
||||
{{ __('Add') }}
|
||||
</Button>
|
||||
</div>
|
||||
<div v-if="assessments.data?.length">
|
||||
<ListView
|
||||
@@ -9,23 +17,76 @@
|
||||
:rows="assessments.data"
|
||||
row-key="name"
|
||||
:options="{
|
||||
selectable: false,
|
||||
showTooltip: false,
|
||||
getRowRoute: (row) => getRowRoute(row),
|
||||
}"
|
||||
>
|
||||
<ListHeader
|
||||
class="mb-2 grid items-center space-x-4 rounded bg-gray-100 p-2"
|
||||
>
|
||||
<ListHeaderItem :item="item" v-for="item in getAssessmentColumns()">
|
||||
<template #prefix="{ item }">
|
||||
<component
|
||||
v-if="item.icon"
|
||||
:is="item.icon"
|
||||
class="h-4 w-4 stroke-1.5 ml-4"
|
||||
/>
|
||||
</template>
|
||||
</ListHeaderItem>
|
||||
</ListHeader>
|
||||
<ListRows>
|
||||
<ListRow :row="row" v-for="row in assessments.data">
|
||||
<template #default="{ column, item }">
|
||||
<ListRowItem :item="row[column.key]" :align="column.align">
|
||||
<div>
|
||||
{{ row[column.key] }}
|
||||
</div>
|
||||
</ListRowItem>
|
||||
</template>
|
||||
</ListRow>
|
||||
</ListRows>
|
||||
<ListSelectBanner>
|
||||
<template #actions="{ unselectAll, selections }">
|
||||
<div class="flex gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
@click="removeAssessments(selections, unselectAll)"
|
||||
>
|
||||
<Trash2 class="h-4 w-4 stroke-1.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</ListSelectBanner>
|
||||
</ListView>
|
||||
</div>
|
||||
<div v-else class="text-sm italic text-gray-600">
|
||||
{{ __('No Assessments') }}
|
||||
</div>
|
||||
</div>
|
||||
<AssessmentModal
|
||||
v-model="showModal"
|
||||
v-model:assessments="assessments"
|
||||
:batch="props.batch"
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ListView, createResource } from 'frappe-ui'
|
||||
import { inject } from 'vue'
|
||||
import {
|
||||
ListView,
|
||||
ListRow,
|
||||
ListRows,
|
||||
ListHeader,
|
||||
ListHeaderItem,
|
||||
ListRowItem,
|
||||
ListSelectBanner,
|
||||
createResource,
|
||||
Button,
|
||||
} from 'frappe-ui'
|
||||
import { inject, ref } from 'vue'
|
||||
import AssessmentModal from '@/components/Modals/AssessmentModal.vue'
|
||||
import { Plus, Trash2 } from 'lucide-vue-next'
|
||||
|
||||
const user = inject('$user')
|
||||
const showModal = ref(false)
|
||||
|
||||
const props = defineProps({
|
||||
batch: {
|
||||
@@ -56,6 +117,28 @@ const assessments = createResource({
|
||||
auto: true,
|
||||
})
|
||||
|
||||
const deleteAssessments = createResource({
|
||||
url: 'lms.lms.api.delete_documents',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doctype: 'LMS Assessment',
|
||||
documents: values.assessments,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const removeAssessments = (selections, unselectAll) => {
|
||||
deleteAssessments.submit(
|
||||
{ assessments: Array.from(selections) },
|
||||
{
|
||||
onSuccess(data) {
|
||||
assessments.reload()
|
||||
unselectAll()
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const getRowRoute = (row) => {
|
||||
if (row.assessment_type == 'LMS Assignment') {
|
||||
if (row.submission) {
|
||||
@@ -85,6 +168,10 @@ const getRowRoute = (row) => {
|
||||
}
|
||||
}
|
||||
|
||||
const canSeeAddButton = () => {
|
||||
return user.data?.is_moderator || user.data?.is_evaluator
|
||||
}
|
||||
|
||||
const getAssessmentColumns = () => {
|
||||
let columns = [
|
||||
{
|
||||
|
||||
@@ -4,15 +4,11 @@
|
||||
<div class="text-xl font-semibold">
|
||||
{{ __('Courses') }}
|
||||
</div>
|
||||
<Button
|
||||
v-if="user.data?.is_moderator"
|
||||
variant="solid"
|
||||
@click="openCourseModal()"
|
||||
>
|
||||
<Button v-if="user.data?.is_moderator" @click="openCourseModal()">
|
||||
<template #prefix>
|
||||
<Plus class="h-4 w-4" />
|
||||
</template>
|
||||
{{ __('Add Course') }}
|
||||
{{ __('Add') }}
|
||||
</Button>
|
||||
</div>
|
||||
<div v-if="courses.data?.length">
|
||||
@@ -88,6 +84,7 @@ import {
|
||||
ListRowItem,
|
||||
} from 'frappe-ui'
|
||||
import { Plus, Trash2 } from 'lucide-vue-next'
|
||||
import { showToast } from '@/utils'
|
||||
|
||||
const showCourseModal = ref(false)
|
||||
const user = inject('$user')
|
||||
@@ -132,23 +129,28 @@ const getCoursesColumns = () => {
|
||||
]
|
||||
}
|
||||
|
||||
const removeCourse = createResource({
|
||||
url: 'frappe.client.delete',
|
||||
const deleteCourses = createResource({
|
||||
url: 'lms.lms.api.delete_documents',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doctype: 'Batch Course',
|
||||
name: values.course,
|
||||
documents: values.courses,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const removeCourses = (selections, unselectAll) => {
|
||||
selections.forEach(async (course) => {
|
||||
removeCourse.submit({ course })
|
||||
})
|
||||
setTimeout(() => {
|
||||
courses.reload()
|
||||
unselectAll()
|
||||
}, 1000)
|
||||
deleteCourses.submit(
|
||||
{
|
||||
courses: Array.from(selections),
|
||||
},
|
||||
{
|
||||
onSuccess(data) {
|
||||
courses.reload()
|
||||
showToast(__('Success'), __('Courses deleted successfully'), 'check')
|
||||
unselectAll()
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<Button class="float-right mb-3" variant="solid" @click="openStudentModal()">
|
||||
<Button class="float-right mb-3" @click="openStudentModal()">
|
||||
<template #prefix>
|
||||
<Plus class="h-4 w-4" />
|
||||
</template>
|
||||
{{ __('Add Student') }}
|
||||
{{ __('Add') }}
|
||||
</Button>
|
||||
<div class="text-lg font-semibold mb-4">
|
||||
{{ __('Students') }}
|
||||
@@ -88,6 +88,7 @@ import {
|
||||
import { Trash2, Plus } from 'lucide-vue-next'
|
||||
import { ref } from 'vue'
|
||||
import StudentModal from '@/components/Modals/StudentModal.vue'
|
||||
import { showToast } from '@/utils'
|
||||
|
||||
const showStudentModal = ref(false)
|
||||
|
||||
@@ -135,23 +136,28 @@ const openStudentModal = () => {
|
||||
showStudentModal.value = true
|
||||
}
|
||||
|
||||
const removeStudent = createResource({
|
||||
url: 'frappe.client.delete',
|
||||
const deleteStudents = createResource({
|
||||
url: 'lms.lms.api.delete_documents',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doctype: 'Batch Student',
|
||||
name: values.student,
|
||||
documents: values.students,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const removeStudents = (selections, unselectAll) => {
|
||||
selections.forEach(async (student) => {
|
||||
removeStudent.submit({ student })
|
||||
})
|
||||
setTimeout(() => {
|
||||
students.reload()
|
||||
unselectAll()
|
||||
}, 500)
|
||||
deleteStudents.submit(
|
||||
{
|
||||
students: Array.from(selections),
|
||||
},
|
||||
{
|
||||
onSuccess(data) {
|
||||
students.reload()
|
||||
showToast(__('Success'), __('Students deleted successfully'), 'check')
|
||||
unselectAll()
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
v-if="title && (outline.data?.length || allowEdit)"
|
||||
class="grid grid-cols-[70%,30%] mb-4 px-2"
|
||||
>
|
||||
<div class="font-semibold text-lg">
|
||||
<div class="font-semibold text-lg leading-5">
|
||||
{{ __(title) }}
|
||||
</div>
|
||||
<Button size="sm" v-if="allowEdit" @click="openChapterModal()">
|
||||
|
||||
86
frontend/src/components/Modals/AssessmentModal.vue
Normal file
86
frontend/src/components/Modals/AssessmentModal.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<Dialog
|
||||
v-model="show"
|
||||
:options="{
|
||||
title: __('Add an assessment'),
|
||||
size: 'sm',
|
||||
actions: [
|
||||
{
|
||||
label: __('Submit'),
|
||||
variant: 'solid',
|
||||
onClick: (close) => addAssessment(close),
|
||||
},
|
||||
],
|
||||
}"
|
||||
>
|
||||
<template #body-content>
|
||||
<div class="space-y-4">
|
||||
<FormControl
|
||||
type="select"
|
||||
:options="assessmentTypes"
|
||||
v-model="assessmentType"
|
||||
:label="__('Type')"
|
||||
/>
|
||||
<Link
|
||||
v-model="assessment"
|
||||
:doctype="assessmentType"
|
||||
:label="__('Assessment')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Dialog, FormControl, createResource } from 'frappe-ui'
|
||||
import Link from '@/components/Controls/Link.vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { showToast } from '@/utils'
|
||||
|
||||
const show = defineModel()
|
||||
const assessmentType = ref(null)
|
||||
const assessment = ref(null)
|
||||
const assessments = defineModel('assessments')
|
||||
|
||||
const props = defineProps({
|
||||
batch: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
})
|
||||
|
||||
const assessmentResource = createResource({
|
||||
url: 'frappe.client.insert',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doc: {
|
||||
doctype: 'LMS Assessment',
|
||||
parent: props.batch,
|
||||
parenttype: 'LMS Batch',
|
||||
parentfield: 'assessment',
|
||||
assessment_type: assessmentType.value,
|
||||
assessment_name: assessment.value,
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const addAssessment = (close) => {
|
||||
assessmentResource.submit(
|
||||
{},
|
||||
{
|
||||
onSuccess(data) {
|
||||
assessments.value.reload()
|
||||
showToast(__('Success'), __('Assessment added successfully'), 'check')
|
||||
close()
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const assessmentTypes = computed(() => {
|
||||
return [
|
||||
{ label: 'Quiz', value: 'LMS Quiz' },
|
||||
{ label: 'Assignment', value: 'LMS Assignment' },
|
||||
]
|
||||
})
|
||||
</script>
|
||||
@@ -15,18 +15,24 @@
|
||||
}"
|
||||
>
|
||||
<template #body-content>
|
||||
<FormControl label="Title" v-model="chapter.title" class="mb-4" />
|
||||
<FormControl
|
||||
ref="chapterInput"
|
||||
label="Title"
|
||||
v-model="chapter.title"
|
||||
class="mb-4"
|
||||
/>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Dialog, FormControl, createResource } from 'frappe-ui'
|
||||
import { defineModel, reactive, watch } from 'vue'
|
||||
import { defineModel, reactive, watch, ref } from 'vue'
|
||||
import { createToast } from '@/utils/'
|
||||
import { capture } from '@/telemetry'
|
||||
|
||||
const show = defineModel()
|
||||
const outline = defineModel('outline')
|
||||
const chapterInput = ref(null)
|
||||
|
||||
const props = defineProps({
|
||||
course: {
|
||||
@@ -37,6 +43,7 @@ const props = defineProps({
|
||||
type: Object,
|
||||
},
|
||||
})
|
||||
|
||||
const chapter = reactive({
|
||||
title: '',
|
||||
})
|
||||
@@ -97,6 +104,7 @@ const addChapter = (close) => {
|
||||
{ name: data.name },
|
||||
{
|
||||
onSuccess(data) {
|
||||
chapter.title = ''
|
||||
outline.value.reload()
|
||||
createToast({
|
||||
text: 'Chapter added successfully',
|
||||
@@ -160,4 +168,12 @@ watch(
|
||||
chapter.title = newChapter?.title
|
||||
}
|
||||
)
|
||||
|
||||
watch(show, () => {
|
||||
if (show.value) {
|
||||
setTimeout(() => {
|
||||
chapterInput.value.$el.querySelector('input').focus()
|
||||
}, 100)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -212,7 +212,8 @@ const questionCreation = createResource({
|
||||
})
|
||||
|
||||
const submitQuestion = (close) => {
|
||||
if (questionData.data?.name) updateQuestion(close)
|
||||
console.log(questionData.data?.name)
|
||||
if (props.questionDetail?.question) updateQuestion(close)
|
||||
else addQuestion(close)
|
||||
}
|
||||
|
||||
@@ -239,7 +240,7 @@ const addQuestion = (close) => {
|
||||
)
|
||||
},
|
||||
onError(err) {
|
||||
showToast(__('Error'), __(err.message?.[0] || err), 'x')
|
||||
showToast(__('Error'), __(err.messages?.[0] || err), 'x')
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -259,7 +260,7 @@ const addQuestionRow = (question, close) => {
|
||||
close()
|
||||
},
|
||||
onError(err) {
|
||||
showToast(__('Error'), __(err.message?.[0] || err), 'x')
|
||||
showToast(__('Error'), __(err.messages?.[0] || err), 'x')
|
||||
close()
|
||||
},
|
||||
}
|
||||
@@ -312,13 +313,12 @@ const updateQuestion = (close) => {
|
||||
quiz.value.reload()
|
||||
close()
|
||||
},
|
||||
onError(err) {
|
||||
showToast(__('Error'), __(err.message?.[0] || err), 'x')
|
||||
close()
|
||||
},
|
||||
}
|
||||
)
|
||||
},
|
||||
onError(err) {
|
||||
showToast(__('Error'), __(err.messages?.[0] || err), 'x')
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,13 +13,9 @@
|
||||
<div class="text-lg font-semibold mb-4">
|
||||
{{ __('Details') }}
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-10 mb-4">
|
||||
<div class="grid grid-cols-2 gap-10 mb-4 space-y-2">
|
||||
<div>
|
||||
<FormControl
|
||||
v-model="batch.title"
|
||||
:label="__('Title')"
|
||||
class="mb-4"
|
||||
/>
|
||||
<FormControl v-model="batch.title" :label="__('Title')" />
|
||||
</div>
|
||||
<div class="flex flex-col space-y-2">
|
||||
<FormControl
|
||||
|
||||
@@ -420,7 +420,7 @@ const validateMandatoryFields = () => {
|
||||
}
|
||||
}
|
||||
if (course.paid_course && (!course.course_price || !course.currency)) {
|
||||
return 'Course price and currency are mandatory for paid courses'
|
||||
return __('Course price and currency are mandatory for paid courses')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,7 +436,7 @@ watch(
|
||||
const validateFile = (file) => {
|
||||
let extension = file.name.split('.').pop().toLowerCase()
|
||||
if (!['jpg', 'jpeg', 'png', 'webp'].includes(extension)) {
|
||||
return 'Only image file is allowed.'
|
||||
return __('Only image file is allowed.')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -541,4 +541,13 @@ updateDocumentTitle(pageMeta)
|
||||
color: #383a42;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.codeBoxTextArea {
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border-top: 3px solid theme('colors.gray.700');
|
||||
border-bottom: 3px solid theme('colors.gray.700');
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -117,7 +117,7 @@ onMounted(() => {
|
||||
const renderEditor = (holder) => {
|
||||
return new EditorJS({
|
||||
holder: holder,
|
||||
tools: getEditorTools(),
|
||||
tools: getEditorTools(true),
|
||||
autofocus: true,
|
||||
})
|
||||
}
|
||||
@@ -143,7 +143,9 @@ const lessonDetails = createResource({
|
||||
Object.keys(data.lesson).forEach((key) => {
|
||||
lesson[key] = data.lesson[key]
|
||||
})
|
||||
lesson.include_in_preview = data.include_in_preview ? true : false
|
||||
lesson.include_in_preview = data?.lesson?.include_in_preview
|
||||
? true
|
||||
: false
|
||||
addLessonContent(data)
|
||||
addInstructorNotes(data)
|
||||
enableAutoSave()
|
||||
@@ -180,7 +182,7 @@ const addInstructorNotes = (data) => {
|
||||
const enableAutoSave = () => {
|
||||
autoSaveInterval = setInterval(() => {
|
||||
saveLesson()
|
||||
}, 5000)
|
||||
}, 10000)
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -423,7 +425,7 @@ const breadcrumbs = computed(() => {
|
||||
},
|
||||
{
|
||||
label: lessonDetails.data?.course_title,
|
||||
route: { name: 'CourseDetail', params: { courseName: props.courseName } },
|
||||
route: { name: 'CourseForm', params: { courseName: props.courseName } },
|
||||
},
|
||||
]
|
||||
|
||||
@@ -549,10 +551,6 @@ updateDocumentTitle(pageMeta)
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.codeBoxSelectItem:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.codeBoxSelectedItem {
|
||||
background-color: lightblue !important;
|
||||
}
|
||||
@@ -570,4 +568,17 @@ updateDocumentTitle(pageMeta)
|
||||
color: #383a42;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.codeBoxTextArea {
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.prose :where(pre):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
|
||||
overflow-x: unset;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border-top: 3px solid theme('colors.gray.700');
|
||||
border-bottom: 3px solid theme('colors.gray.700');
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"
|
||||
/>
|
||||
<div v-if="quizDetails.data?.name">
|
||||
<div class="grid grid-cols-3 gap-5 mt-2 mb-8">
|
||||
<div class="grid grid-cols-3 gap-5 mt-4 mb-8">
|
||||
<FormControl
|
||||
v-model="quiz.max_attempts"
|
||||
:label="__('Maximun Attempts')"
|
||||
@@ -125,7 +125,7 @@
|
||||
<div class="flex gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
@click="deleteQuizzes(selections, unselectAll)"
|
||||
@click="deleteQuestions(selections, unselectAll)"
|
||||
>
|
||||
<Trash2 class="h-4 w-4 stroke-1.5" />
|
||||
</Button>
|
||||
@@ -174,7 +174,7 @@ import {
|
||||
} from 'vue'
|
||||
import { Plus, Trash2 } from 'lucide-vue-next'
|
||||
import Question from '@/components/Modals/Question.vue'
|
||||
import { showToast } from '../utils'
|
||||
import { showToast, updateDocumentTitle } from '@/utils'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const showQuestionModal = ref(false)
|
||||
@@ -306,7 +306,7 @@ const createQuiz = () => {
|
||||
onSuccess(data) {
|
||||
showToast(__('Success'), __('Quiz created successfully'), 'check')
|
||||
router.push({
|
||||
name: 'QuizCreation',
|
||||
name: 'QuizForm',
|
||||
params: { quizID: data.name },
|
||||
})
|
||||
},
|
||||
@@ -375,24 +375,29 @@ const openQuestionModal = (question = null) => {
|
||||
showQuestionModal.value = true
|
||||
}
|
||||
|
||||
const deleteQuiz = createResource({
|
||||
url: 'frappe.client.delete',
|
||||
const deleteQuestionResource = createResource({
|
||||
url: 'lms.lms.api.delete_documents',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doctype: 'LMS Quiz Question',
|
||||
name: values.quiz,
|
||||
documents: values.questions,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const deleteQuizzes = (selections, unselectAll) => {
|
||||
selections.forEach(async (quiz) => {
|
||||
deleteQuiz.submit({ quiz })
|
||||
})
|
||||
setTimeout(() => {
|
||||
quizDetails.reload()
|
||||
unselectAll()
|
||||
}, 500)
|
||||
const deleteQuestions = (selections, unselectAll) => {
|
||||
deleteQuestionResource.submit(
|
||||
{
|
||||
questions: Array.from(selections),
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
showToast(__('Success'), __('Questions deleted successfully'), 'check')
|
||||
quizDetails.reload()
|
||||
unselectAll()
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const breadcrumbs = computed(() => {
|
||||
@@ -410,9 +415,18 @@ const breadcrumbs = computed(() => {
|
||||
})
|
||||
} */
|
||||
crumbs.push({
|
||||
label: props.quizID == 'new' ? 'New Quiz' : quizDetails.data?.title,
|
||||
route: { name: 'QuizCreation', params: { quizID: props.quizID } },
|
||||
label: props.quizID == 'new' ? __('New Quiz') : quizDetails.data?.title,
|
||||
route: { name: 'QuizForm', params: { quizID: props.quizID } },
|
||||
})
|
||||
return crumbs
|
||||
})
|
||||
|
||||
const pageMeta = computed(() => {
|
||||
return {
|
||||
title: props.quizID == 'new' ? __('New Quiz') : quizDetails.data?.title,
|
||||
description: __('Form to create and edit quizzes'),
|
||||
}
|
||||
})
|
||||
|
||||
updateDocumentTitle(pageMeta)
|
||||
</script>
|
||||
@@ -5,7 +5,7 @@
|
||||
<Breadcrumbs :items="breadcrumbs" />
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'QuizCreation',
|
||||
name: 'QuizForm',
|
||||
params: {
|
||||
quizID: 'new',
|
||||
},
|
||||
@@ -36,7 +36,7 @@
|
||||
<router-link
|
||||
v-for="row in quizzes.data"
|
||||
:to="{
|
||||
name: 'QuizCreation',
|
||||
name: 'QuizForm',
|
||||
params: {
|
||||
quizID: row.name,
|
||||
},
|
||||
@@ -62,6 +62,7 @@ import {
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed, inject, onMounted } from 'vue'
|
||||
import { Plus } from 'lucide-vue-next'
|
||||
import { updateDocumentTitle } from '@/utils'
|
||||
|
||||
const user = inject('$user')
|
||||
const router = useRouter()
|
||||
@@ -123,4 +124,13 @@ const breadcrumbs = computed(() => {
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
const pageMeta = computed(() => {
|
||||
return {
|
||||
title: __('Quizzes'),
|
||||
description: __('List of quizzes'),
|
||||
}
|
||||
})
|
||||
|
||||
updateDocumentTitle(pageMeta)
|
||||
</script>
|
||||
|
||||
@@ -154,8 +154,8 @@ const routes = [
|
||||
},
|
||||
{
|
||||
path: '/quizzes/:quizID',
|
||||
name: 'QuizCreation',
|
||||
component: () => import('@/pages/QuizCreation.vue'),
|
||||
name: 'QuizForm',
|
||||
component: () => import('@/pages/QuizForm.vue'),
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -149,9 +149,9 @@ export function getEditorTools() {
|
||||
class: CodeBox,
|
||||
config: {
|
||||
themeURL:
|
||||
'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.18.1/build/styles/dracula.min.css', // Optional
|
||||
themeName: 'atom-one-dark', // Optional
|
||||
useDefaultTheme: 'dark', // Optional. This also determines the background color of the language select drop-down
|
||||
'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.18.1/build/styles/atom-one-dark.min.css',
|
||||
themeName: 'atom-one-dark',
|
||||
useDefaultTheme: 'dark',
|
||||
},
|
||||
},
|
||||
list: {
|
||||
|
||||
@@ -699,3 +699,10 @@ def save_certificate_details(
|
||||
doc.update(details)
|
||||
doc.insert()
|
||||
return doc.name
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def delete_documents(doctype, documents):
|
||||
frappe.only_for("Moderator")
|
||||
for doc in documents:
|
||||
frappe.delete_doc(doctype, doc)
|
||||
|
||||
Reference in New Issue
Block a user