feat: read only mode
This commit is contained in:
@@ -39,7 +39,11 @@
|
||||
{{ __('More') }}
|
||||
</span>
|
||||
</div>
|
||||
<Button v-if="isModerator" variant="ghost" @click="openPageModal()">
|
||||
<Button
|
||||
v-if="isModerator && !readOnlyMode"
|
||||
variant="ghost"
|
||||
@click="openPageModal()"
|
||||
>
|
||||
<template #icon>
|
||||
<Plus class="h-4 w-4 text-ink-gray-7 stroke-1.5" />
|
||||
</template>
|
||||
@@ -63,6 +67,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-2 flex flex-col gap-1">
|
||||
<div
|
||||
v-if="readOnlyMode && !sidebarStore.isSidebarCollapsed"
|
||||
class="z-10 m-2 bg-surface-modal py-2.5 px-3 text-xs text-ink-gray-7 leading-5 rounded-md"
|
||||
>
|
||||
{{
|
||||
__(
|
||||
'This site is being updated. You will not be able to make any changes. Full access will be restored shortly.'
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
<TrialBanner
|
||||
v-if="
|
||||
userResource.data?.is_system_manager && userResource.data?.is_fc_site
|
||||
@@ -89,15 +103,31 @@
|
||||
: 'flex-row space-x-3'
|
||||
"
|
||||
>
|
||||
<Tooltip v-if="readOnlyMode && sidebarStore.isSidebarCollapsed">
|
||||
<CircleAlert
|
||||
class="size-4 stroke-1.5 text-ink-gray-7 cursor-pointer"
|
||||
/>
|
||||
<template #body>
|
||||
<div
|
||||
class="max-w-[30ch] rounded bg-surface-gray-7 px-2 py-1 text-center text-p-xs text-ink-white shadow-xl"
|
||||
>
|
||||
{{
|
||||
__(
|
||||
'This site is being updated. You will not be able to make any changes. Full access will be restored shortly.'
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
</Tooltip>
|
||||
<Tooltip :text="__('Powered by Learning')">
|
||||
<Zap
|
||||
class="size-4 stroke-1.5 text-gray-700 cursor-pointer"
|
||||
class="size-4 stroke-1.5 text-ink-gray-7 cursor-pointer"
|
||||
@click="redirectToWebsite()"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :text="__('Help')">
|
||||
<CircleHelp
|
||||
class="size-4 stroke-1.5 text-gray-700 cursor-pointer"
|
||||
class="size-4 stroke-1.5 text-ink-gray-7 cursor-pointer"
|
||||
@click="
|
||||
() => {
|
||||
showHelpModal = minimize ? true : !showHelpModal
|
||||
@@ -113,7 +143,7 @@
|
||||
"
|
||||
>
|
||||
<CollapseSidebar
|
||||
class="size-4 text-gray-700 duration-300 stroke-1.5 ease-in-out cursor-pointer"
|
||||
class="size-4 text-ink-gray-7 duration-300 stroke-1.5 ease-in-out cursor-pointer"
|
||||
:class="{
|
||||
'[transform:rotateY(180deg)]': sidebarStore.isSidebarCollapsed,
|
||||
}"
|
||||
@@ -166,6 +196,7 @@ import { useRouter } from 'vue-router'
|
||||
import InviteIcon from './Icons/InviteIcon.vue'
|
||||
import {
|
||||
BookOpen,
|
||||
CircleAlert,
|
||||
ChevronRight,
|
||||
Plus,
|
||||
CircleHelp,
|
||||
@@ -203,6 +234,7 @@ const currentStep = ref({})
|
||||
const router = useRouter()
|
||||
let onboardingDetails
|
||||
let isOnboardingStepsCompleted = false
|
||||
const readOnlyMode = window.read_only_mode
|
||||
const iconProps = {
|
||||
strokeWidth: 1.5,
|
||||
width: 16,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="text-lg font-semibold text-ink-gray-9">
|
||||
{{ __('Assessments') }}
|
||||
</div>
|
||||
<Button v-if="canSeeAddButton()" @click="showModal = true">
|
||||
<Button v-if="canAddAssessments()" @click="showModal = true">
|
||||
<template #prefix>
|
||||
<Plus class="h-4 w-4" />
|
||||
</template>
|
||||
@@ -100,6 +100,7 @@ import { Plus, Trash2 } from 'lucide-vue-next'
|
||||
|
||||
const user = inject('$user')
|
||||
const showModal = ref(false)
|
||||
const readOnlyMode = window.read_only_mode
|
||||
|
||||
const props = defineProps({
|
||||
batch: {
|
||||
@@ -181,7 +182,8 @@ const getRowRoute = (row) => {
|
||||
}
|
||||
}
|
||||
|
||||
const canSeeAddButton = () => {
|
||||
const canAddAssessments = () => {
|
||||
if (readOnlyMode) return false
|
||||
return user.data?.is_moderator || user.data?.is_evaluator
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ import {
|
||||
} from 'frappe-ui'
|
||||
import { Plus, Trash2 } from 'lucide-vue-next'
|
||||
import { showToast } from '@/utils'
|
||||
const readOnlyMode = window.read_only_mode
|
||||
|
||||
const showCourseModal = ref(false)
|
||||
const user = inject('$user')
|
||||
@@ -159,6 +160,9 @@ const removeCourses = (selections, unselectAll) => {
|
||||
}
|
||||
|
||||
const canSeeAddButton = () => {
|
||||
if (readOnlyMode) {
|
||||
return false
|
||||
}
|
||||
return user.data?.is_moderator || user.data?.is_evaluator
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -111,7 +111,6 @@ import {
|
||||
FormControl,
|
||||
ListView,
|
||||
ListHeader,
|
||||
ListHeaderItem,
|
||||
ListRows,
|
||||
ListRow,
|
||||
ListRowItem,
|
||||
|
||||
@@ -49,68 +49,70 @@
|
||||
{{ batch.data.timezone }}
|
||||
</span>
|
||||
</div>
|
||||
<router-link
|
||||
v-if="isModerator || isStudent"
|
||||
:to="{
|
||||
name: 'Batch',
|
||||
params: {
|
||||
batchName: batch.data.name,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<Button variant="solid" class="w-full mt-4">
|
||||
<span>
|
||||
{{ isModerator ? __('Manage Batch') : __('Visit Batch') }}
|
||||
</span>
|
||||
<div v-if="!readOnlyMode">
|
||||
<router-link
|
||||
v-if="isModerator || isStudent"
|
||||
:to="{
|
||||
name: 'Batch',
|
||||
params: {
|
||||
batchName: batch.data.name,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<Button variant="solid" class="w-full mt-4">
|
||||
<span>
|
||||
{{ isModerator ? __('Manage Batch') : __('Visit Batch') }}
|
||||
</span>
|
||||
</Button>
|
||||
</router-link>
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'Billing',
|
||||
params: {
|
||||
type: 'batch',
|
||||
name: batch.data.name,
|
||||
},
|
||||
}"
|
||||
v-else-if="
|
||||
batch.data.paid_batch &&
|
||||
batch.data.seats_left > 0 &&
|
||||
batch.data.accept_enrollments
|
||||
"
|
||||
>
|
||||
<Button v-if="!isStudent" class="w-full mt-4" variant="solid">
|
||||
<span>
|
||||
{{ __('Register Now') }}
|
||||
</span>
|
||||
</Button>
|
||||
</router-link>
|
||||
<Button
|
||||
variant="solid"
|
||||
class="w-full mt-2"
|
||||
v-else-if="
|
||||
batch.data.allow_self_enrollment &&
|
||||
batch.data.seats_left &&
|
||||
batch.data.accept_enrollments
|
||||
"
|
||||
@click="enrollInBatch()"
|
||||
>
|
||||
{{ __('Enroll Now') }}
|
||||
</Button>
|
||||
</router-link>
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'Billing',
|
||||
params: {
|
||||
type: 'batch',
|
||||
name: batch.data.name,
|
||||
},
|
||||
}"
|
||||
v-else-if="
|
||||
batch.data.paid_batch &&
|
||||
batch.data.seats_left > 0 &&
|
||||
batch.data.accept_enrollments
|
||||
"
|
||||
>
|
||||
<Button v-if="!isStudent" class="w-full mt-4" variant="solid">
|
||||
<span>
|
||||
{{ __('Register Now') }}
|
||||
</span>
|
||||
</Button>
|
||||
</router-link>
|
||||
<Button
|
||||
variant="solid"
|
||||
class="w-full mt-2"
|
||||
v-else-if="
|
||||
batch.data.allow_self_enrollment &&
|
||||
batch.data.seats_left &&
|
||||
batch.data.accept_enrollments
|
||||
"
|
||||
@click="enrollInBatch()"
|
||||
>
|
||||
{{ __('Enroll Now') }}
|
||||
</Button>
|
||||
<router-link
|
||||
v-if="isModerator"
|
||||
:to="{
|
||||
name: 'BatchForm',
|
||||
params: {
|
||||
batchName: batch.data.name,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<Button class="w-full mt-2">
|
||||
<span>
|
||||
{{ __('Edit') }}
|
||||
</span>
|
||||
</Button>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="isModerator"
|
||||
:to="{
|
||||
name: 'BatchForm',
|
||||
params: {
|
||||
batchName: batch.data.name,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<Button class="w-full mt-2">
|
||||
<span>
|
||||
{{ __('Edit') }}
|
||||
</span>
|
||||
</Button>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
@@ -123,7 +125,7 @@ import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const user = inject('$user')
|
||||
const dayjs = inject('$dayjs')
|
||||
const readOnlyMode = window.read_only_mode
|
||||
|
||||
const props = defineProps({
|
||||
batch: {
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
<div class="text-ink-gray-7 font-medium">
|
||||
{{ __('Students') }}
|
||||
</div>
|
||||
<Button @click="openStudentModal()">
|
||||
<Button v-if="!readOnlyMode" @click="openStudentModal()">
|
||||
<template #prefix>
|
||||
<Plus class="h-4 w-4" />
|
||||
</template>
|
||||
@@ -247,6 +247,7 @@ const chartData = ref(null)
|
||||
const chartOptions = ref(null)
|
||||
const showProgressChart = ref(false)
|
||||
const assessmentCount = ref(0)
|
||||
const readOnlyMode = window.read_only_mode
|
||||
|
||||
const props = defineProps({
|
||||
batch: {
|
||||
|
||||
@@ -9,89 +9,94 @@
|
||||
<div v-if="course.data.paid_course" class="text-2xl font-semibold mb-3">
|
||||
{{ course.data.price }}
|
||||
</div>
|
||||
<div v-if="course.data.membership" class="space-y-2">
|
||||
<div v-if="!readOnlyMode">
|
||||
<div v-if="course.data.membership" class="space-y-2">
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'Lesson',
|
||||
params: {
|
||||
courseName: course.name,
|
||||
chapterNumber: course.data.current_lesson
|
||||
? course.data.current_lesson.split('-')[0]
|
||||
: 1,
|
||||
lessonNumber: course.data.current_lesson
|
||||
? course.data.current_lesson.split('-')[1]
|
||||
: 1,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<Button variant="solid" size="md" class="w-full">
|
||||
<span>
|
||||
{{ __('Continue Learning') }}
|
||||
</span>
|
||||
</Button>
|
||||
</router-link>
|
||||
<CertificationLinks :courseName="course.data.name" class="w-full" />
|
||||
</div>
|
||||
<router-link
|
||||
v-else-if="course.data.paid_course"
|
||||
:to="{
|
||||
name: 'Lesson',
|
||||
name: 'Billing',
|
||||
params: {
|
||||
courseName: course.name,
|
||||
chapterNumber: course.data.current_lesson
|
||||
? course.data.current_lesson.split('-')[0]
|
||||
: 1,
|
||||
lessonNumber: course.data.current_lesson
|
||||
? course.data.current_lesson.split('-')[1]
|
||||
: 1,
|
||||
type: 'course',
|
||||
name: course.data.name,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<Button variant="solid" size="md" class="w-full">
|
||||
<span>
|
||||
{{ __('Continue Learning') }}
|
||||
{{ __('Buy this course') }}
|
||||
</span>
|
||||
</Button>
|
||||
</router-link>
|
||||
<Badge
|
||||
v-else-if="course.data.disable_self_learning"
|
||||
theme="blue"
|
||||
size="lg"
|
||||
>
|
||||
{{ __('Contact the Administrator to enroll for this course.') }}
|
||||
</Badge>
|
||||
<Button
|
||||
v-else
|
||||
@click="enrollStudent()"
|
||||
variant="solid"
|
||||
class="w-full"
|
||||
size="md"
|
||||
>
|
||||
<span>
|
||||
{{ __('Start Learning') }}
|
||||
</span>
|
||||
</Button>
|
||||
<Button
|
||||
v-if="canGetCertificate"
|
||||
@click="fetchCertificate()"
|
||||
variant="subtle"
|
||||
class="w-full mt-2"
|
||||
size="md"
|
||||
>
|
||||
{{ __('Get Certificate') }}
|
||||
</Button>
|
||||
<router-link
|
||||
v-if="user?.data?.is_moderator || is_instructor()"
|
||||
:to="{
|
||||
name: 'CourseForm',
|
||||
params: {
|
||||
courseName: course.data.name,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<Button variant="subtle" class="w-full mt-2" size="md">
|
||||
<span>
|
||||
{{ __('Edit') }}
|
||||
</span>
|
||||
</Button>
|
||||
</router-link>
|
||||
<CertificationLinks :courseName="course.data.name" class="w-full" />
|
||||
</div>
|
||||
<router-link
|
||||
v-else-if="course.data.paid_course"
|
||||
:to="{
|
||||
name: 'Billing',
|
||||
params: {
|
||||
type: 'course',
|
||||
name: course.data.name,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<Button variant="solid" size="md" class="w-full">
|
||||
<span>
|
||||
{{ __('Buy this course') }}
|
||||
</span>
|
||||
</Button>
|
||||
</router-link>
|
||||
<Badge
|
||||
v-else-if="course.data.disable_self_learning"
|
||||
theme="blue"
|
||||
size="lg"
|
||||
>
|
||||
{{ __('Contact the Administrator to enroll for this course.') }}
|
||||
</Badge>
|
||||
<Button
|
||||
v-else
|
||||
@click="enrollStudent()"
|
||||
variant="solid"
|
||||
class="w-full"
|
||||
size="md"
|
||||
>
|
||||
<span>
|
||||
{{ __('Start Learning') }}
|
||||
</span>
|
||||
</Button>
|
||||
<Button
|
||||
v-if="canGetCertificate"
|
||||
@click="fetchCertificate()"
|
||||
variant="subtle"
|
||||
class="w-full mt-2"
|
||||
size="md"
|
||||
>
|
||||
{{ __('Get Certificate') }}
|
||||
</Button>
|
||||
<router-link
|
||||
v-if="user?.data?.is_moderator || is_instructor()"
|
||||
:to="{
|
||||
name: 'CourseForm',
|
||||
params: {
|
||||
courseName: course.data.name,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<Button variant="subtle" class="w-full mt-2" size="md">
|
||||
<span>
|
||||
{{ __('Edit') }}
|
||||
</span>
|
||||
</Button>
|
||||
</router-link>
|
||||
<div class="space-y-4">
|
||||
<div class="mt-8 font-medium text-ink-gray-9">
|
||||
<div
|
||||
class="font-medium text-ink-gray-9"
|
||||
:class="{ 'mt-8': !readOnlyMode }"
|
||||
>
|
||||
{{ __('This course has:') }}
|
||||
</div>
|
||||
<div class="flex items-center text-ink-gray-9">
|
||||
@@ -149,6 +154,7 @@ import CertificationLinks from '@/components/CertificationLinks.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const user = inject('$user')
|
||||
const readOnlyMode = window.read_only_mode
|
||||
|
||||
const props = defineProps({
|
||||
course: {
|
||||
|
||||
@@ -8,18 +8,6 @@
|
||||
<AppSidebar />
|
||||
</div>
|
||||
<div class="w-full overflow-auto" id="scrollContainer">
|
||||
<div
|
||||
v-if="readOnlyMode"
|
||||
class="right-0 top-0 mb-3 bg-surface-gray-2 py-3 text-sm text-ink-gray-5"
|
||||
>
|
||||
<div class="mx-auto px-10">
|
||||
{{
|
||||
__(
|
||||
'This site is running in read-only mode. Full functionality will be restored soon.'
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
@@ -28,6 +16,4 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import AppSidebar from './AppSidebar.vue'
|
||||
|
||||
const readOnlyMode = window.read_only_mode
|
||||
</script>
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
</span>
|
||||
</div>
|
||||
<Dropdown
|
||||
v-if="user.data.name == reply.owner && !reply.editable"
|
||||
v-if="
|
||||
user.data.name == reply.owner && !reply.editable && !readOnlyMode
|
||||
"
|
||||
:options="[
|
||||
{
|
||||
label: 'Edit',
|
||||
@@ -71,7 +73,7 @@
|
||||
</div>
|
||||
|
||||
<TextEditor
|
||||
v-if="renderEditor"
|
||||
v-if="renderEditor && !readOnlyMode"
|
||||
class="mt-5"
|
||||
:content="newReply"
|
||||
:mentions="mentionUsers"
|
||||
@@ -80,7 +82,7 @@
|
||||
:fixedMenu="true"
|
||||
editorClass="ProseMirror prose prose-table:table-fixed prose-td:p-2 prose-th:p-2 prose-td:border prose-th:border prose-td:border-outline-gray-2 prose-th:border-outline-gray-2 prose-td:relative prose-th:relative prose-th:bg-surface-gray-2 prose-sm max-w-none border border-outline-gray-2 rounded-b-md min-h-[7rem] py-1 px-2"
|
||||
/>
|
||||
<div class="flex justify-between mt-2">
|
||||
<div v-if="!readOnlyMode" class="flex justify-between mt-2">
|
||||
<span> </span>
|
||||
<Button @click="postReply()">
|
||||
<span>
|
||||
@@ -105,6 +107,7 @@ const user = inject('$user')
|
||||
const allUsers = inject('$allUsers')
|
||||
const mentionUsers = ref([])
|
||||
const renderEditor = ref(false)
|
||||
const readOnlyMode = window.read_only_mode
|
||||
|
||||
const props = defineProps({
|
||||
topic: {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<Button v-if="!singleThread" class="float-right" @click="openTopicModal()">
|
||||
<Button
|
||||
v-if="!singleThread && !readOnlyMode"
|
||||
class="float-right"
|
||||
@click="openTopicModal()"
|
||||
>
|
||||
{{ __('New {0}').format(singularize(title)) }}
|
||||
</Button>
|
||||
<div class="text-xl font-semibold text-ink-gray-9">
|
||||
@@ -77,6 +81,7 @@ const currentTopic = ref(null)
|
||||
const socket = inject('$socket')
|
||||
const user = inject('$user')
|
||||
const showTopicModal = ref(false)
|
||||
const readOnlyMode = window.read_only_mode
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="text-lg font-semibold text-ink-gray-9">
|
||||
{{ __('Live Class') }}
|
||||
</div>
|
||||
<Button v-if="user.data.is_moderator" @click="openLiveClassModal">
|
||||
<Button v-if="canCreateClass()" @click="openLiveClassModal">
|
||||
<template #prefix>
|
||||
<Plus class="h-4 w-4" />
|
||||
</template>
|
||||
@@ -87,6 +87,7 @@ import { formatTime } from '@/utils/'
|
||||
const user = inject('$user')
|
||||
const showLiveClassModal = ref(false)
|
||||
const dayjs = inject('$dayjs')
|
||||
const readOnlyMode = window.read_only_mode
|
||||
|
||||
const props = defineProps({
|
||||
batch: {
|
||||
@@ -116,6 +117,11 @@ const liveClasses = createListResource({
|
||||
const openLiveClassModal = () => {
|
||||
showLiveClassModal.value = true
|
||||
}
|
||||
|
||||
const canCreateClass = () => {
|
||||
if (readOnlyMode) return false
|
||||
return user.data?.is_moderator || user.data?.is_evaluator
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.short-introduction {
|
||||
|
||||
Reference in New Issue
Block a user