feat: configuration to disable pwa

This commit is contained in:
Jannat Patel
2025-12-10 18:05:50 +05:30
parent 0877e32e1b
commit 80a217e646
11 changed files with 46 additions and 68 deletions

View File

@@ -3,7 +3,7 @@
<Layout class="isolate text-base"> <Layout class="isolate text-base">
<router-view /> <router-view />
</Layout> </Layout>
<InstallPrompt v-if="isMobile" /> <InstallPrompt v-if="isMobile && !settings.data?.disable_pwa" />
<Dialogs /> <Dialogs />
</FrappeUIProvider> </FrappeUIProvider>
</template> </template>
@@ -13,6 +13,7 @@ import { Dialogs } from '@/utils/dialogs'
import { computed, onUnmounted, ref, watch } from 'vue' import { computed, onUnmounted, ref, watch } from 'vue'
import { useScreenSize } from './utils/composables' import { useScreenSize } from './utils/composables'
import { usersStore } from '@/stores/user' import { usersStore } from '@/stores/user'
import { useSettings } from '@/stores/settings'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { posthogSettings } from '@/telemetry' import { posthogSettings } from '@/telemetry'
import DesktopLayout from './components/DesktopLayout.vue' import DesktopLayout from './components/DesktopLayout.vue'
@@ -24,6 +25,7 @@ const { isMobile } = useScreenSize()
const router = useRouter() const router = useRouter()
const noSidebar = ref(false) const noSidebar = ref(false)
const { userResource } = usersStore() const { userResource } = usersStore()
const { settings } = useSettings()
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
if (to.query.fromLesson || to.path === '/persona') { if (to.query.fromLesson || to.path === '/persona') {

View File

@@ -48,7 +48,7 @@ const settingsStore = useSettings()
const sendMail = (close: Function) => { const sendMail = (close: Function) => {
call('frappe.core.doctype.communication.email.make', { call('frappe.core.doctype.communication.email.make', {
recipients: settingsStore.contactUsEmail?.data, recipients: settingsStore.settings?.data?.contact_us_email,
subject: subject.value, subject: subject.value,
content: message.value, content: message.value,
send_email: true, send_email: true,

View File

@@ -120,6 +120,13 @@ const tabsStructure = computed(() => {
description: description:
'If enabled, users will no able to move forward in a video', 'If enabled, users will no able to move forward in a video',
}, },
{
label: 'Disable PWA',
name: 'disable_pwa',
type: 'checkbox',
description:
'If checked, users will not be able to install the application as a Progressive Web App.',
},
{ {
label: 'Send calendar invite for evaluations', label: 'Send calendar invite for evaluations',
name: 'send_calendar_invite_for_evaluations', name: 'send_calendar_invite_for_evaluations',

View File

@@ -239,8 +239,7 @@ const showPageModal = ref(false)
const isModerator = ref(false) const isModerator = ref(false)
const isInstructor = ref(false) const isInstructor = ref(false)
const pageToEdit = ref(null) const pageToEdit = ref(null)
const settingsStore = useSettings() const { settings, sidebarSettings, activeTab, isSettingsOpen } = useSettings()
const { sidebarSettings } = settingsStore
const showOnboarding = ref(false) const showOnboarding = ref(false)
const showIntermediateModal = ref(false) const showIntermediateModal = ref(false)
const currentStep = ref({}) const currentStep = ref({})
@@ -393,7 +392,7 @@ const addPrograms = async () => {
} }
const addContactUsDetails = () => { const addContactUsDetails = () => {
if (!settingsStore.contactUsEmail?.data && !settingsStore.contactUsURL?.data) if (!settings?.data?.contact_us_email && !settings?.data?.contact_us_url)
return return
const contactUsLinkExists = sidebarLinks.value.some( const contactUsLinkExists = sidebarLinks.value.some(
@@ -403,10 +402,10 @@ const addContactUsDetails = () => {
sidebarLinks.value.push({ sidebarLinks.value.push({
label: 'Contact Us', label: 'Contact Us',
icon: settingsStore.contactUsURL?.data ? 'Headset' : 'Mail', icon: settings.data?.contact_us_url ? 'Headset' : 'Mail',
to: settingsStore.contactUsURL?.data to: settings.data?.contact_us_url
? settingsStore.contactUsURL.data ? settings.data?.contact_us_url
: settingsStore.contactUsEmail?.data, : settings.data?.contact_us_email,
}) })
} }
@@ -540,8 +539,8 @@ const steps = reactive([
completed: false, completed: false,
onClick: () => { onClick: () => {
minimize.value = true minimize.value = true
settingsStore.activeTab = 'Members' activeTab.value = 'Members'
settingsStore.isSettingsOpen = true isSettingsOpen.value = true
}, },
}, },
{ {

View File

@@ -171,7 +171,7 @@ const showQuizLoader = ref(false)
const quizLoadTimer = ref(0) const quizLoadTimer = ref(0)
const currentQuiz = ref(null) const currentQuiz = ref(null)
const nextQuiz = ref({}) const nextQuiz = ref({})
const { preventSkippingVideos } = useSettings() const { settings } = useSettings()
const props = defineProps({ const props = defineProps({
file: { file: {
@@ -299,7 +299,7 @@ const toggleMute = () => {
const changeCurrentTime = () => { const changeCurrentTime = () => {
if ( if (
preventSkippingVideos.data && settings.data?.prevent_skipping_videos &&
currentTime.value > videoRef.value.currentTime currentTime.value > videoRef.value.currentTime
) )
return return

View File

@@ -168,7 +168,7 @@ const testCaseSection = ref<HTMLElement | null>(null)
const testCases = ref<TestCase[]>([]) const testCases = ref<TestCase[]>([])
const boilerplate = ref<string>('') const boilerplate = ref<string>('')
const { brand } = sessionStore() const { brand } = sessionStore()
const { livecodeURL } = useSettings() const { settings } = useSettings()
const router = useRouter() const router = useRouter()
const fromLesson = ref(false) const fromLesson = ref(false)
const falconURL = ref<string>('https://falcon.frappe.io/') const falconURL = ref<string>('https://falcon.frappe.io/')
@@ -291,8 +291,8 @@ watch(
) )
const loadFalcon = () => { const loadFalcon = () => {
if (livecodeURL.data) { if (settings.data) {
falconURL.value = livecodeURL.data falconURL.value = settings.data.livecode_url
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const script = document.createElement('script') const script = document.createElement('script')

View File

@@ -270,7 +270,7 @@ let router = createRouter({
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
const { userResource } = usersStore() const { userResource } = usersStore()
let { isLoggedIn } = sessionStore() let { isLoggedIn } = sessionStore()
const { allowGuestAccess } = useSettings() const { settings } = useSettings()
try { try {
if (isLoggedIn) { if (isLoggedIn) {
@@ -283,8 +283,8 @@ router.beforeEach(async (to, from, next) => {
if (!isLoggedIn) { if (!isLoggedIn) {
if (to.name == 'Home') router.push({ name: 'Courses' }) if (to.name == 'Home') router.push({ name: 'Courses' })
await allowGuestAccess.promise await settings.promise
if (!allowGuestAccess.data) { if (!settings.data.allow_guest_access) {
window.location.href = '/login' window.location.href = '/login'
return return
} }

View File

@@ -7,32 +7,10 @@ export const useSettings = defineStore('settings', () => {
const isSettingsOpen = ref(false) const isSettingsOpen = ref(false)
const activeTab = ref(null) const activeTab = ref(null)
const allowGuestAccess = createResource({ const settings = createResource({
url: 'lms.lms.api.get_lms_setting', url: 'lms.lms.api.get_lms_settings',
params: { field: 'allow_guest_access' },
auto: true, auto: true,
cache: ['allowGuestAccess'], cache: 'LMS Settings',
})
const preventSkippingVideos = createResource({
url: 'lms.lms.api.get_lms_setting',
params: { field: 'prevent_skipping_videos' },
auto: true,
cache: ['preventSkippingVideos'],
})
const contactUsEmail = createResource({
url: 'lms.lms.api.get_lms_setting',
params: { field: 'contact_us_email' },
auto: true,
cache: ['contactUsEmail'],
})
const contactUsURL = createResource({
url: 'lms.lms.api.get_lms_setting',
params: { field: 'contact_us_url' },
auto: true,
cache: ['contactUsURL'],
}) })
const sidebarSettings = createResource({ const sidebarSettings = createResource({
@@ -41,21 +19,10 @@ export const useSettings = defineStore('settings', () => {
auto: false, auto: false,
}) })
const livecodeURL = createResource({
url: 'lms.lms.api.get_lms_setting',
params: { field: 'livecode_url' },
auto: true,
cache: ['livecodeURL'],
})
return { return {
isSettingsOpen, isSettingsOpen,
activeTab, activeTab,
allowGuestAccess, settings,
preventSkippingVideos,
contactUsEmail,
contactUsURL,
sidebarSettings, sidebarSettings,
livecodeURL,
} }
}) })

View File

@@ -612,7 +612,7 @@ const setupPlyrForVideo = (video, players) => {
const current_time = player.currentTime const current_time = player.currentTime
const newTime = getTargetTime(player, e) const newTime = getTargetTime(player, e)
if ( if (
useSettings().preventSkippingVideos.data && useSettings().settings.data?.prevent_skipping_videos &&
parseFloat(newTime) > current_time parseFloat(newTime) > current_time
) { ) {
e.preventDefault() e.preventDefault()

View File

@@ -1304,25 +1304,21 @@ def get_notifications(filters):
@frappe.whitelist(allow_guest=True) @frappe.whitelist(allow_guest=True)
def get_lms_setting(field=None): def get_lms_settings():
if not field:
frappe.throw(_("Field name is required"))
frappe.log_error("Field name is missing when accessing LMS Settings {0} {1} {2}").format(
frappe.local.request_ip, frappe.get_request_header("Referer"), frappe.get_request_header("Origin")
)
allowed_fields = [ allowed_fields = [
"allow_guest_access", "allow_guest_access",
"prevent_skipping_videos", "prevent_skipping_videos",
"contact_us_email", "contact_us_email",
"contact_us_url", "contact_us_url",
"livecode_url", "livecode_url",
"disable_pwa",
] ]
if field not in allowed_fields: settings = frappe._dict()
frappe.throw(_("You are not allowed to access this field")) for field in allowed_fields:
settings[field] = frappe.get_cached_value("LMS Settings", None, field)
return frappe.get_cached_value("LMS Settings", None, field) return settings
@frappe.whitelist() @frappe.whitelist()

View File

@@ -12,6 +12,7 @@
"column_break_zdel", "column_break_zdel",
"allow_guest_access", "allow_guest_access",
"prevent_skipping_videos", "prevent_skipping_videos",
"disable_pwa",
"column_break_bjis", "column_break_bjis",
"unsplash_access_key", "unsplash_access_key",
"livecode_url", "livecode_url",
@@ -438,13 +439,19 @@
"fieldname": "certifications", "fieldname": "certifications",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Certifications" "label": "Certifications"
},
{
"default": "0",
"fieldname": "disable_pwa",
"fieldtype": "Check",
"label": "Disable PWA"
} }
], ],
"grid_page_length": 50, "grid_page_length": 50,
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2025-12-02 12:21:15.832799", "modified": "2025-12-10 17:36:15.689695",
"modified_by": "sayali@frappe.io", "modified_by": "sayali@frappe.io",
"module": "LMS", "module": "LMS",
"name": "LMS Settings", "name": "LMS Settings",