feat: configurable frontend base path
Co-authored-by: Suraj Shetty <surajshetty3416@users.noreply.github.com>
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
"dev": "vite",
|
||||
"serve": "vite preview",
|
||||
"build": "vite build --base=/assets/lms/frontend/ && yarn copy-html-entry && yarn copy-colors-json",
|
||||
"copy-html-entry": "cp ../lms/public/frontend/index.html ../lms/www/lms.html",
|
||||
"copy-html-entry": "cp ../lms/public/frontend/index.html ../lms/www/_lms.html",
|
||||
"copy-colors-json": "cp node_modules/frappe-ui/tailwind/colors.json src/utils/frappe-ui-colors.json"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -65,6 +65,7 @@ import { Dialog, FormControl } from 'frappe-ui'
|
||||
import { nextTick, onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { Link } from 'frappe-ui/frappe'
|
||||
import { getLmsRoute } from '@/utils/basePath'
|
||||
|
||||
const show = ref(false)
|
||||
const quiz = ref(null)
|
||||
@@ -94,7 +95,10 @@ const addAssessment = () => {
|
||||
}
|
||||
|
||||
const redirectToForm = () => {
|
||||
if (props.type == 'quiz') window.open('/lms/quizzes?new=true', '_blank')
|
||||
else window.open('/lms/assignments?new=true', '_blank')
|
||||
if (props.type == 'quiz') {
|
||||
window.open(getLmsRoute('quizzes?new=true'), '_blank')
|
||||
} else {
|
||||
window.open(getLmsRoute('assignments?new=true'), '_blank')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -248,6 +248,7 @@ import DateRange from '@/components/Common/DateRange.vue'
|
||||
import BulkCertificates from '@/components/Modals/BulkCertificates.vue'
|
||||
import BatchFeedback from '@/components/BatchFeedback.vue'
|
||||
import dayjs from 'dayjs/esm'
|
||||
import { getLmsRoute } from '@/utils/basePath'
|
||||
|
||||
const user = inject('$user')
|
||||
const showAnnouncementModal = ref(false)
|
||||
@@ -357,7 +358,9 @@ const isStudent = computed(() => {
|
||||
})
|
||||
|
||||
const redirectToLogin = () => {
|
||||
window.location.href = `/login?redirect-to=/lms/batches/${props.batchName}`
|
||||
window.location.href = `/login?redirect-to=${getLmsRoute(
|
||||
`batches/${props.batchName}`
|
||||
)}`
|
||||
}
|
||||
|
||||
const openAnnouncementModal = () => {
|
||||
|
||||
@@ -207,14 +207,18 @@
|
||||
:text="access.data.message"
|
||||
:buttonLabel="type == 'course' ? 'Checkout Course' : 'Checkout Batch'"
|
||||
:buttonLink="
|
||||
type == 'course' ? `/lms/courses/${name}` : `/lms/batches/${name}`
|
||||
type == 'course'
|
||||
? getLmsRoute(`courses/${name}`)
|
||||
: getLmsRoute(`batches/${name}`)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="!user.data?.name">
|
||||
<NotPermitted
|
||||
text="Please login to access this page."
|
||||
:buttonLink="`/login?redirect-to=/lms/billing/${type}/${name}`"
|
||||
:buttonLink="`/login?redirect-to=${getLmsRoute(
|
||||
`billing/${type}/${name}`
|
||||
)}`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -235,6 +239,7 @@ import Link from '@/components/Controls/Link.vue'
|
||||
import NotPermitted from '@/components/NotPermitted.vue'
|
||||
import { X } from 'lucide-vue-next'
|
||||
import { useTelemetry } from 'frappe-ui/frappe'
|
||||
import { getLmsRoute } from '@/utils/basePath'
|
||||
|
||||
const user = inject('$user')
|
||||
const { brand } = sessionStore()
|
||||
@@ -441,11 +446,11 @@ const changeCurrency = (country) => {
|
||||
|
||||
const redirectTo = computed(() => {
|
||||
if (props.type == 'course') {
|
||||
return `/lms/courses/${props.name}`
|
||||
return getLmsRoute(`courses/${props.name}`)
|
||||
} else if (props.type == 'batch') {
|
||||
return `/lms/batches/${props.name}`
|
||||
return getLmsRoute(`batches/${props.name}`)
|
||||
} else if (props.type == 'certificate') {
|
||||
return `/lms/courses/${props.name}/certification`
|
||||
return getLmsRoute(`courses/${props.name}/certification`)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -378,6 +378,7 @@ import CourseOutline from '@/components/CourseOutline.vue'
|
||||
import UserAvatar from '@/components/UserAvatar.vue'
|
||||
import Notes from '@/components/Notes/Notes.vue'
|
||||
import InlineLessonMenu from '@/components/Notes/InlineLessonMenu.vue'
|
||||
import { getLmsRoute } from '@/utils/basePath'
|
||||
|
||||
const user = inject('$user')
|
||||
const socket = inject('$socket')
|
||||
@@ -902,7 +903,9 @@ watch(allowDiscussions, () => {
|
||||
})
|
||||
|
||||
const redirectToLogin = () => {
|
||||
window.location.href = `/login?redirect-to=/lms/courses/${props.courseName}`
|
||||
window.location.href = `/login?redirect-to=${getLmsRoute(
|
||||
`courses/${props.courseName}`
|
||||
)}`
|
||||
}
|
||||
|
||||
usePageMeta(() => {
|
||||
|
||||
@@ -122,6 +122,7 @@ import { X, LinkedinIcon, Twitter } from 'lucide-vue-next'
|
||||
import { sessionStore } from '@/stores/session'
|
||||
import { decodeEntities } from '@/utils'
|
||||
import DOMPurify from 'dompurify'
|
||||
import { getLmsRoute } from '@/utils/basePath'
|
||||
|
||||
const dayjs = inject('$dayjs')
|
||||
const { branding } = sessionStore()
|
||||
@@ -158,7 +159,9 @@ const badges = createResource({
|
||||
const shareOnSocial = (badge, medium) => {
|
||||
let shareUrl
|
||||
const url = encodeURIComponent(
|
||||
`${window.location.origin}/lms/badges/${badge.badge}/${props.profile.data?.email}`
|
||||
`${window.location.origin}${getLmsRoute(
|
||||
`badges/${badge.badge}/${props.profile.data?.email}`
|
||||
)}`
|
||||
)
|
||||
const summary = `I am happy to announce that I earned the ${
|
||||
badge.badge
|
||||
|
||||
@@ -158,6 +158,7 @@ import { sessionStore } from '@/stores/session'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { openSettings } from '@/utils'
|
||||
import { useSettings } from '@/stores/settings'
|
||||
import { getLmsRoute } from '@/utils/basePath'
|
||||
|
||||
const user = inject<any>('$user')
|
||||
const code = ref<string | null>('')
|
||||
@@ -255,7 +256,10 @@ const updateBoilerPlate = () => {
|
||||
|
||||
const checkIfUserIsPermitted = (doc: any = null) => {
|
||||
if (!user.data) {
|
||||
window.location.href = `/login?redirect-to=/lms/programming-exercises/${props.exerciseID}/submission/${props.submissionID}`
|
||||
const redirectPath = getLmsRoute(
|
||||
`programming-exercises/${props.exerciseID}/submission/${props.submissionID}`
|
||||
)
|
||||
window.location.href = `/login?redirect-to=${redirectPath}`
|
||||
}
|
||||
|
||||
if (!doc) return
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { usersStore } from './stores/user'
|
||||
import { sessionStore } from './stores/session'
|
||||
import { useSettings } from './stores/settings'
|
||||
import { getLmsBasePath } from './utils/basePath'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@@ -268,7 +269,7 @@ const routes = [
|
||||
]
|
||||
|
||||
let router = createRouter({
|
||||
history: createWebHistory('/lms'),
|
||||
history: createWebHistory(`/${getLmsBasePath()}`),
|
||||
routes,
|
||||
})
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import translationPlugin from '../translation'
|
||||
import { usersStore } from '@/stores/user'
|
||||
import { call } from 'frappe-ui'
|
||||
import router from '@/router'
|
||||
import { getLmsRoute } from '@/utils/basePath'
|
||||
|
||||
export class Assignment {
|
||||
constructor({ data, api, readOnly }) {
|
||||
@@ -53,7 +54,10 @@ export class Assignment {
|
||||
fieldname: ['name'],
|
||||
}).then((data) => {
|
||||
let submission = data.name || 'new'
|
||||
this.wrapper.innerHTML = `<iframe src="/lms/assignment-submission/${assignment}/${submission}?fromLesson=1" class="w-full h-[500px]"></iframe>`
|
||||
const submissionPath = getLmsRoute(
|
||||
`assignment-submission/${assignment}/${submission}?fromLesson=1`
|
||||
)
|
||||
this.wrapper.innerHTML = `<iframe src="${submissionPath}" class="w-full h-[500px]"></iframe>`
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
12
frontend/src/utils/basePath.js
Normal file
12
frontend/src/utils/basePath.js
Normal file
@@ -0,0 +1,12 @@
|
||||
export function getLmsBasePath() {
|
||||
return window.lms_path || 'lms'
|
||||
}
|
||||
|
||||
export function getLmsRoute(path = '') {
|
||||
const base = getLmsBasePath()
|
||||
if (!path) {
|
||||
return base
|
||||
}
|
||||
const normalized = path.startsWith('/') ? path.slice(1) : path
|
||||
return `/${base}/${normalized}`
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import translationPlugin from '@/translation'
|
||||
import ProgrammingExerciseModal from '@/pages/ProgrammingExercises/ProgrammingExerciseModal.vue';
|
||||
import { call } from 'frappe-ui';
|
||||
import { usersStore } from '@/stores/user'
|
||||
import { getLmsRoute } from '@/utils/basePath'
|
||||
|
||||
|
||||
export class Program {
|
||||
@@ -73,7 +74,10 @@ export class Program {
|
||||
fieldname: ['name'],
|
||||
}).then((data: { name: string }) => {
|
||||
let submission = data.name || 'new'
|
||||
this.wrapper.innerHTML = `<iframe src="/lms/programming-exercises/${exercise}/submission/${submission}?fromLesson=1" class="w-full h-[900px] border rounded-md"></iframe>`
|
||||
const submissionPath = getLmsRoute(
|
||||
`programming-exercises/${exercise}/submission/${submission}?fromLesson=1`
|
||||
)
|
||||
this.wrapper.innerHTML = `<iframe src="${submissionPath}" class="w-full h-[900px] border rounded-md"></iframe>`
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -100,4 +104,4 @@ export class Program {
|
||||
exercise: this.data.exercise,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { usersStore } from '../stores/user'
|
||||
import translationPlugin from '../translation'
|
||||
import { CircleHelp } from 'lucide-vue-next'
|
||||
import router from '@/router'
|
||||
import { getLmsRoute } from '@/utils/basePath'
|
||||
|
||||
export class Quiz {
|
||||
constructor({ data, api, readOnly }) {
|
||||
@@ -42,7 +43,8 @@ export class Quiz {
|
||||
|
||||
renderQuiz(quiz) {
|
||||
if (this.readOnly) {
|
||||
this.wrapper.innerHTML = `<iframe src="/lms/quiz/${quiz}?fromLesson=1" class="w-full h-[500px]"></iframe>`
|
||||
const quizPath = getLmsRoute(`quiz/${quiz}?fromLesson=1`)
|
||||
this.wrapper.innerHTML = `<iframe src="${quizPath}" class="w-full h-[500px]"></iframe>`
|
||||
return
|
||||
}
|
||||
this.wrapper.innerHTML = `<div class='border rounded-md p-4 text-center bg-surface-menu-bar mb-4'>
|
||||
|
||||
@@ -17,7 +17,7 @@ export default defineConfig(async ({ mode }) => {
|
||||
lucideIcons: true,
|
||||
jinjaBootData: true,
|
||||
buildConfig: {
|
||||
indexHtmlPath: '../lms/www/lms.html',
|
||||
indexHtmlPath: '../lms/www/_lms.html',
|
||||
},
|
||||
}),
|
||||
vue(),
|
||||
|
||||
Reference in New Issue
Block a user