Merge pull request #1537 from frappe/develop
chore: merge 'develop' into 'main'
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
describe("Course Creation", () => {
|
||||
it("creates a new course", () => {
|
||||
cy.login();
|
||||
cy.wait(1000);
|
||||
cy.wait(500);
|
||||
cy.visit("/lms/courses");
|
||||
|
||||
// Close onboarding modal
|
||||
cy.closeOnboardingModal();
|
||||
|
||||
// Create a course
|
||||
cy.get("button").contains("New").click();
|
||||
cy.wait(1000);
|
||||
cy.wait(500);
|
||||
cy.url().should("include", "/courses/new/edit");
|
||||
|
||||
cy.get("label").contains("Title").type("Test Course");
|
||||
@@ -96,7 +99,8 @@ describe("Course Creation", () => {
|
||||
// View Course
|
||||
cy.wait(1000);
|
||||
cy.visit("/lms");
|
||||
cy.wait(500);
|
||||
cy.closeOnboardingModal();
|
||||
|
||||
cy.url().should("include", "/lms/courses");
|
||||
cy.get(".grid a:first").within(() => {
|
||||
cy.get("div").contains("Test Course");
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
|
||||
import "cypress-file-upload";
|
||||
import "cypress-real-events";
|
||||
|
||||
Cypress.Commands.add("login", (email, password) => {
|
||||
if (!email) {
|
||||
@@ -68,3 +69,11 @@ Cypress.Commands.add("paste", { prevSubject: true }, (subject, text) => {
|
||||
element.dispatchEvent(event);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("closeOnboardingModal", () => {
|
||||
cy.wait(500);
|
||||
cy.get('[class*="z-50"]')
|
||||
.find('button:has(svg[class*="feather-x"])')
|
||||
.realClick();
|
||||
cy.wait(1000);
|
||||
});
|
||||
|
||||
3
frontend/components.d.ts
vendored
3
frontend/components.d.ts
vendored
@@ -47,11 +47,14 @@ declare module 'vue' {
|
||||
Discussions: typeof import('./src/components/Discussions.vue')['default']
|
||||
EditCoverImage: typeof import('./src/components/Modals/EditCoverImage.vue')['default']
|
||||
EditProfile: typeof import('./src/components/Modals/EditProfile.vue')['default']
|
||||
EmailTemplateModal: typeof import('./src/components/Modals/EmailTemplateModal.vue')['default']
|
||||
EmailTemplates: typeof import('./src/components/EmailTemplates.vue')['default']
|
||||
EmptyState: typeof import('./src/components/EmptyState.vue')['default']
|
||||
EvaluationModal: typeof import('./src/components/Modals/EvaluationModal.vue')['default']
|
||||
Evaluators: typeof import('./src/components/Evaluators.vue')['default']
|
||||
Event: typeof import('./src/components/Modals/Event.vue')['default']
|
||||
ExplanationVideos: typeof import('./src/components/Modals/ExplanationVideos.vue')['default']
|
||||
FeedbackModal: typeof import('./src/components/Modals/FeedbackModal.vue')['default']
|
||||
FrappeCloudIcon: typeof import('./src/components/Icons/FrappeCloudIcon.vue')['default']
|
||||
IconPicker: typeof import('./src/components/Controls/IconPicker.vue')['default']
|
||||
IndicatorIcon: typeof import('./src/components/Icons/IndicatorIcon.vue')['default']
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"codemirror-editor-vue3": "^2.8.0",
|
||||
"dayjs": "^1.11.6",
|
||||
"feather-icons": "^4.28.0",
|
||||
"frappe-ui": "^0.1.143",
|
||||
"frappe-ui": "^0.1.147",
|
||||
"highlight.js": "^11.11.1",
|
||||
"lucide-vue-next": "^0.383.0",
|
||||
"markdown-it": "^14.0.0",
|
||||
|
||||
@@ -9,18 +9,14 @@
|
||||
<script setup>
|
||||
import { FrappeUIProvider } from 'frappe-ui'
|
||||
import { Dialogs } from '@/utils/dialogs'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, onUnmounted, ref } from 'vue'
|
||||
import { useScreenSize } from './utils/composables'
|
||||
import DesktopLayout from './components/DesktopLayout.vue'
|
||||
import MobileLayout from './components/MobileLayout.vue'
|
||||
import NoSidebarLayout from './components/NoSidebarLayout.vue'
|
||||
import { stopSession } from '@/telemetry'
|
||||
import { init as initTelemetry } from '@/telemetry'
|
||||
import { usersStore } from '@/stores/user'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const screenSize = useScreenSize()
|
||||
let { userResource } = usersStore()
|
||||
const router = useRouter()
|
||||
const noSidebar = ref(false)
|
||||
|
||||
@@ -39,13 +35,9 @@ const Layout = computed(() => {
|
||||
}
|
||||
if (screenSize.width < 640) {
|
||||
return MobileLayout
|
||||
} else {
|
||||
return DesktopLayout
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
if (userResource.data) await initTelemetry()
|
||||
return DesktopLayout
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
|
||||
@@ -181,7 +181,6 @@
|
||||
import UserDropdown from '@/components/UserDropdown.vue'
|
||||
import CollapseSidebar from '@/components/Icons/CollapseSidebar.vue'
|
||||
import SidebarLink from '@/components/SidebarLink.vue'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import { ref, onMounted, inject, watch, reactive, markRaw, h } from 'vue'
|
||||
import { getSidebarLinks } from '../utils'
|
||||
import { usersStore } from '@/stores/user'
|
||||
@@ -244,6 +243,7 @@ const iconProps = {
|
||||
onMounted(() => {
|
||||
addNotifications()
|
||||
setSidebarLinks()
|
||||
setUpOnboarding()
|
||||
socket.on('publish_lms_notifications', (data) => {
|
||||
unreadNotifications.reload()
|
||||
})
|
||||
@@ -388,10 +388,6 @@ const deletePage = (link) => {
|
||||
)
|
||||
}
|
||||
|
||||
const getSidebarFromStorage = () => {
|
||||
return useStorage('sidebar_is_collapsed', false)
|
||||
}
|
||||
|
||||
const toggleSidebar = () => {
|
||||
sidebarStore.isSidebarCollapsed = !sidebarStore.isSidebarCollapsed
|
||||
localStorage.setItem(
|
||||
@@ -438,6 +434,7 @@ const steps = reactive([
|
||||
title: __('Add your first chapter'),
|
||||
icon: markRaw(h(FolderTree, iconProps)),
|
||||
completed: false,
|
||||
dependsOn: 'create_first_course',
|
||||
onClick: async () => {
|
||||
minimize.value = true
|
||||
let course = await getFirstCourse()
|
||||
@@ -453,6 +450,7 @@ const steps = reactive([
|
||||
title: __('Add your first lesson'),
|
||||
icon: markRaw(h(FileText, iconProps)),
|
||||
completed: false,
|
||||
dependsOn: 'create_first_chapter',
|
||||
onClick: async () => {
|
||||
minimize.value = true
|
||||
let course = await getFirstCourse()
|
||||
@@ -471,6 +469,7 @@ const steps = reactive([
|
||||
title: __('Create your first quiz'),
|
||||
icon: markRaw(h(CircleHelp, iconProps)),
|
||||
completed: false,
|
||||
dependsOn: 'create_first_course',
|
||||
onClick: () => {
|
||||
minimize.value = true
|
||||
router.push({ name: 'Quizzes' })
|
||||
@@ -502,6 +501,7 @@ const steps = reactive([
|
||||
title: __('Add students to your batch'),
|
||||
icon: markRaw(h(UserPlus, iconProps)),
|
||||
completed: false,
|
||||
dependsOn: 'create_first_batch',
|
||||
onClick: async () => {
|
||||
minimize.value = true
|
||||
let batch = await getFirstBatch()
|
||||
@@ -522,6 +522,7 @@ const steps = reactive([
|
||||
title: __('Add courses to your batch'),
|
||||
icon: markRaw(h(BookText, iconProps)),
|
||||
completed: false,
|
||||
dependsOn: 'create_first_batch',
|
||||
onClick: async () => {
|
||||
minimize.value = true
|
||||
let batch = await getFirstBatch()
|
||||
|
||||
@@ -1,44 +1,49 @@
|
||||
<template>
|
||||
<div v-if="user.data?.is_student">
|
||||
<div
|
||||
v-if="feedbackList.data?.length"
|
||||
class="bg-surface-blue-2 text-blue-700 p-2 rounded-md mb-5"
|
||||
>
|
||||
{{ __('Thank you for providing your feedback!') }}
|
||||
</div>
|
||||
<div v-else class="flex justify-between items-center mb-5">
|
||||
<div class="text-lg font-semibold">
|
||||
{{ __('Help Us Improve') }}
|
||||
<div>
|
||||
<div class="leading-5 mb-4">
|
||||
<div v-if="readOnly">
|
||||
{{ __('Thank you for providing your feedback.') }}
|
||||
<span
|
||||
@click="showFeedbackForm = !showFeedbackForm"
|
||||
class="underline cursor-pointer"
|
||||
>{{ __('Click here') }}</span
|
||||
>
|
||||
{{ __('to view your feedback.') }}
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ __('Help us improve by providing your feedback.') }}
|
||||
</div>
|
||||
</div>
|
||||
<Button @click="submitFeedback()">
|
||||
{{ __('Submit') }}
|
||||
</Button>
|
||||
</div>
|
||||
<div class="space-y-8">
|
||||
<div class="flex items-center justify-between">
|
||||
<Rating
|
||||
v-for="key in ratingKeys"
|
||||
v-model="feedback[key]"
|
||||
:label="__(convertToTitleCase(key))"
|
||||
<div class="space-y-4" :class="showFeedbackForm ? 'block' : 'hidden'">
|
||||
<div class="space-y-4">
|
||||
<Rating
|
||||
v-for="key in ratingKeys"
|
||||
v-model="feedback[key]"
|
||||
:label="__(convertToTitleCase(key))"
|
||||
:readonly="readOnly"
|
||||
/>
|
||||
</div>
|
||||
<FormControl
|
||||
v-model="feedback.feedback"
|
||||
type="textarea"
|
||||
:label="__('Feedback')"
|
||||
:rows="9"
|
||||
:readonly="readOnly"
|
||||
/>
|
||||
<Button v-if="!readOnly" @click="submitFeedback">
|
||||
{{ __('Submit Feedback') }}
|
||||
</Button>
|
||||
</div>
|
||||
<FormControl
|
||||
v-model="feedback.feedback"
|
||||
type="textarea"
|
||||
:label="__('Feedback')"
|
||||
:rows="7"
|
||||
:readonly="readOnly"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="feedbackList.data?.length">
|
||||
<div class="text-lg font-semibold mb-5">
|
||||
{{ __('Average of Feedback Received') }}
|
||||
<div class="leading-5 text-sm mb-2 mt-5">
|
||||
{{ __('Average Feedback Received') }}
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between mb-10">
|
||||
<div class="space-y-4">
|
||||
<Rating
|
||||
v-for="key in ratingKeys"
|
||||
v-model="average[key]"
|
||||
@@ -47,81 +52,32 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="text-lg font-semibold mb-5">
|
||||
{{ __('All Feedback') }}
|
||||
</div>
|
||||
<ListView
|
||||
:columns="feedbackColumns"
|
||||
:rows="feedbackList.data"
|
||||
row-key="name"
|
||||
:options="{
|
||||
showTooltip: false,
|
||||
rowHeight: 'h-16',
|
||||
selectable: false,
|
||||
}"
|
||||
>
|
||||
<ListHeader
|
||||
class="mb-2 grid items-center space-x-4 rounded bg-surface-gray-2 p-2"
|
||||
></ListHeader>
|
||||
<ListRows>
|
||||
<ListRow
|
||||
:row="row"
|
||||
v-for="row in feedbackList.data"
|
||||
class="group cursor-pointer feedback-list"
|
||||
>
|
||||
<template #default="{ column, item }">
|
||||
<ListRowItem
|
||||
:item="row[column.key]"
|
||||
:align="column.align"
|
||||
class="text-sm"
|
||||
>
|
||||
<template #prefix>
|
||||
<div v-if="column.key == 'member_name'">
|
||||
<Avatar
|
||||
class="flex"
|
||||
:image="row['member_image']"
|
||||
:label="item"
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="ratingKeys.includes(column.key)">
|
||||
<Rating v-model="row[column.key]" :readonly="true" />
|
||||
</div>
|
||||
<div v-else class="leading-5">
|
||||
{{ row[column.key] }}
|
||||
</div>
|
||||
</ListRowItem>
|
||||
</template>
|
||||
</ListRow>
|
||||
</ListRows>
|
||||
</ListView>
|
||||
<Button variant="outline" class="mt-5" @click="showAllFeedback = true">
|
||||
{{ __('View all feedback') }}
|
||||
</Button>
|
||||
</div>
|
||||
<div v-else class="text-sm italic text-center text-ink-gray-7 mt-5">
|
||||
<div v-else class="text-ink-gray-7 mt-5 leading-5">
|
||||
{{ __('No feedback received yet.') }}
|
||||
</div>
|
||||
<FeedbackModal
|
||||
v-if="feedbackList.data?.length"
|
||||
v-model="showAllFeedback"
|
||||
:feedbackList="feedbackList.data"
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed, inject, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { inject, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { convertToTitleCase } from '@/utils'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
createListResource,
|
||||
FormControl,
|
||||
ListView,
|
||||
ListHeader,
|
||||
ListRows,
|
||||
ListRow,
|
||||
ListRowItem,
|
||||
Rating,
|
||||
} from 'frappe-ui'
|
||||
import { Button, createListResource, FormControl, Rating } from 'frappe-ui'
|
||||
import FeedbackModal from '@/components/Modals/FeedbackModal.vue'
|
||||
|
||||
const user = inject('$user')
|
||||
const ratingKeys = ['content', 'instructors', 'value']
|
||||
const readOnly = ref(false)
|
||||
const average = reactive({})
|
||||
const feedback = reactive({})
|
||||
const showFeedbackForm = ref(true)
|
||||
const showAllFeedback = ref(false)
|
||||
|
||||
const props = defineProps({
|
||||
batch: {
|
||||
@@ -167,6 +123,7 @@ watch(
|
||||
if (feedbackList.data.length) {
|
||||
let data = feedbackList.data
|
||||
readOnly.value = true
|
||||
showFeedbackForm.value = false
|
||||
|
||||
ratingKeys.forEach((key) => {
|
||||
average[key] = 0
|
||||
@@ -201,40 +158,11 @@ const submitFeedback = () => {
|
||||
{
|
||||
onSuccess: () => {
|
||||
feedbackList.reload()
|
||||
showFeedbackForm.value = false
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const feedbackColumns = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: 'Member',
|
||||
key: 'member_name',
|
||||
width: '10rem',
|
||||
},
|
||||
{
|
||||
label: 'Feedback',
|
||||
key: 'feedback',
|
||||
width: '15rem',
|
||||
},
|
||||
{
|
||||
label: 'Content',
|
||||
key: 'content',
|
||||
width: '9rem',
|
||||
},
|
||||
{
|
||||
label: 'Instructors',
|
||||
key: 'instructors',
|
||||
width: '9rem',
|
||||
},
|
||||
{
|
||||
label: 'Value',
|
||||
key: 'value',
|
||||
width: '9rem',
|
||||
},
|
||||
]
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
.feedback-list > button > div {
|
||||
|
||||
@@ -6,103 +6,59 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-5 mb-8">
|
||||
<div
|
||||
class="flex items-center border py-2 px-3 rounded-md text-ink-gray-7"
|
||||
>
|
||||
<div class="p-2 rounded-md bg-surface-gray-2 mr-3">
|
||||
<User class="w-5 h-5 stroke-1.5" />
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="font-semibold">
|
||||
{{ students.data?.length }}
|
||||
</span>
|
||||
<span class="">
|
||||
{{ __('Students') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex items-center border py-2 px-3 rounded-md text-ink-gray-7"
|
||||
>
|
||||
<div class="p-2 rounded-md bg-surface-gray-2 mr-3">
|
||||
<GraduationCap class="w-5 h-5 stroke-1.5" />
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="font-semibold">
|
||||
{{ certificationCount.data }}
|
||||
</span>
|
||||
<span class="">
|
||||
{{ __('Certified') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex items-center border py-2 px-3 rounded-md text-ink-gray-7"
|
||||
>
|
||||
<div class="p-2 rounded-md bg-surface-gray-2 mr-3">
|
||||
<BookOpen class="w-5 h-5 stroke-1.5" />
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="font-semibold">
|
||||
{{ batch.data.courses?.length }}
|
||||
</span>
|
||||
<span>
|
||||
{{ __('Courses') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex items-center border py-2 px-3 rounded-md text-ink-gray-7"
|
||||
>
|
||||
<div class="p-2 rounded-md bg-surface-gray-2 mr-3">
|
||||
<ShieldCheck class="w-5 h-5 stroke-1.5" />
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="font-semibold">
|
||||
{{ assessmentCount }}
|
||||
</span>
|
||||
<span>
|
||||
{{ __('Assessments') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showProgressChart" class="mb-8">
|
||||
<div class="text-ink-gray-7 font-medium">
|
||||
{{ __('Progress') }}
|
||||
</div>
|
||||
<ApexChart
|
||||
:options="chartOptions"
|
||||
:series="chartData"
|
||||
type="bar"
|
||||
:height="chartData[0].data.length * 30 + 100"
|
||||
<NumberChart
|
||||
class="border rounded-md"
|
||||
:config="{ title: __('Students'), value: students.data?.length || 0 }"
|
||||
/>
|
||||
|
||||
<NumberChart
|
||||
class="border rounded-md"
|
||||
:config="{
|
||||
title: __('Certified'),
|
||||
value: certificationCount.data || 0,
|
||||
}"
|
||||
/>
|
||||
|
||||
<NumberChart
|
||||
class="border rounded-md"
|
||||
:config="{
|
||||
title: __('Courses'),
|
||||
value: batch.data.courses?.length || 0,
|
||||
}"
|
||||
/>
|
||||
|
||||
<NumberChart
|
||||
class="border rounded-md"
|
||||
:config="{ title: __('Assessments'), value: assessmentCount || 0 }"
|
||||
/>
|
||||
<div
|
||||
class="flex items-center justify-center text-sm text-ink-gray-7 space-x-4"
|
||||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<div
|
||||
class="w-3 h-3 rounded-sm"
|
||||
:style="{ 'background-color': theme.colors.green[600] }"
|
||||
></div>
|
||||
<div>
|
||||
{{ __('Courses') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<div
|
||||
class="w-3 h-3 rounded-sm"
|
||||
:style="{ 'background-color': theme.colors.blue[600] }"
|
||||
></div>
|
||||
<div>
|
||||
{{ __('Assessments') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AxisChart
|
||||
v-if="showProgressChart"
|
||||
:config="{
|
||||
data: chartData,
|
||||
title: __('Batch Summary'),
|
||||
subtitle: __('Progress of students in courses and assessments'),
|
||||
xAxis: {
|
||||
key: 'task',
|
||||
title: 'Tasks',
|
||||
type: 'category',
|
||||
},
|
||||
yAxis: {
|
||||
title: __('Number of Students'),
|
||||
echartOptions: {
|
||||
minInterval: 1,
|
||||
},
|
||||
},
|
||||
swapXY: true,
|
||||
series: [
|
||||
{
|
||||
name: 'value',
|
||||
type: 'bar',
|
||||
},
|
||||
],
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -214,6 +170,7 @@
|
||||
<script setup>
|
||||
import {
|
||||
Avatar,
|
||||
AxisChart,
|
||||
Button,
|
||||
createResource,
|
||||
FeatherIcon,
|
||||
@@ -224,6 +181,7 @@ import {
|
||||
ListRows,
|
||||
ListView,
|
||||
ListRowItem,
|
||||
NumberChart,
|
||||
toast,
|
||||
} from 'frappe-ui'
|
||||
import {
|
||||
@@ -245,7 +203,6 @@ const showStudentModal = ref(false)
|
||||
const showStudentProgressModal = ref(false)
|
||||
const selectedStudent = ref(null)
|
||||
const chartData = ref(null)
|
||||
const chartOptions = ref(null)
|
||||
const showProgressChart = ref(false)
|
||||
const assessmentCount = ref(0)
|
||||
const readOnlyMode = window.read_only_mode
|
||||
@@ -333,96 +290,49 @@ const removeStudents = (selections, unselectAll) => {
|
||||
}
|
||||
|
||||
const getChartData = () => {
|
||||
let categories = {}
|
||||
let tasks = []
|
||||
let data = []
|
||||
|
||||
if (!students.data?.length) return []
|
||||
|
||||
Object.keys(students.data[0].courses).forEach((course) => {
|
||||
categories[course] = {
|
||||
value: 0,
|
||||
type: 'course',
|
||||
label: course,
|
||||
}
|
||||
students.data.forEach((row) => {
|
||||
tasks = countAssessments(row, tasks)
|
||||
tasks = countCourses(row, tasks)
|
||||
})
|
||||
|
||||
Object.keys(students.data?.[0].assessments).forEach((assessment) => {
|
||||
categories[assessment] = {
|
||||
value: 0,
|
||||
type: 'assessment',
|
||||
label: assessment,
|
||||
}
|
||||
})
|
||||
|
||||
students.data.forEach((student) => {
|
||||
Object.keys(student.courses).forEach((course) => {
|
||||
if (student.courses[course] === 100) {
|
||||
categories[course].value += 1
|
||||
}
|
||||
})
|
||||
|
||||
Object.keys(student.assessments).forEach((assessment) => {
|
||||
if (student.assessments[assessment].result === 'Pass') {
|
||||
categories[assessment].value += 1
|
||||
}
|
||||
tasks.forEach((task) => {
|
||||
data.push({
|
||||
task: task.label,
|
||||
value: task.value,
|
||||
})
|
||||
})
|
||||
|
||||
chartOptions.value = getChartOptions(categories)
|
||||
return [
|
||||
{
|
||||
name: __('Completed by Students'),
|
||||
data: Object.values(categories).map((item) => item.value),
|
||||
},
|
||||
]
|
||||
return data
|
||||
}
|
||||
|
||||
const getChartOptions = (categories) => {
|
||||
const courseColor = theme.colors.green[700]
|
||||
const assessmentColor = theme.colors.blue[700]
|
||||
const maxY =
|
||||
students.data?.length % 5
|
||||
? students.data?.length + (5 - (students.data?.length % 5))
|
||||
: students.data?.length
|
||||
const countAssessments = (row, tasks) => {
|
||||
Object.keys(row.assessments).forEach((assessment) => {
|
||||
if (row.assessments[assessment].result === 'Pass') {
|
||||
tasks.filter((task) => task.label === assessment).length
|
||||
? tasks.filter((task) => task.label === assessment)[0].value++
|
||||
: tasks.push({
|
||||
value: 1,
|
||||
label: assessment,
|
||||
})
|
||||
}
|
||||
})
|
||||
return tasks
|
||||
}
|
||||
|
||||
return {
|
||||
chart: {
|
||||
type: 'bar',
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
distributed: true,
|
||||
borderRadius: 3,
|
||||
borderRadiusApplication: 'end',
|
||||
horizontal: true,
|
||||
barHeight: '40%',
|
||||
},
|
||||
},
|
||||
colors: Object.values(categories).map((item) =>
|
||||
item.type === 'course' ? courseColor : assessmentColor
|
||||
),
|
||||
xaxis: {
|
||||
categories: Object.values(categories).map((item) => item.label),
|
||||
labels: {
|
||||
style: {
|
||||
fontSize: '10px',
|
||||
},
|
||||
rotate: 0,
|
||||
formatter: function (value) {
|
||||
return value.length > 30 ? `${value.substring(0, 30)}...` : value
|
||||
},
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
max: maxY,
|
||||
min: 0,
|
||||
stepSize: 10,
|
||||
tickAmount: maxY / 5,
|
||||
/* reversed: true */
|
||||
},
|
||||
}
|
||||
const countCourses = (row, tasks) => {
|
||||
Object.keys(row.courses).forEach((course) => {
|
||||
if (row.courses[course] === 100) {
|
||||
tasks.filter((task) => task.label === course).length
|
||||
? tasks.filter((task) => task.label === course)[0].value++
|
||||
: tasks.push({
|
||||
value: 1,
|
||||
label: course,
|
||||
})
|
||||
}
|
||||
})
|
||||
return tasks
|
||||
}
|
||||
|
||||
watch(students, () => {
|
||||
@@ -442,8 +352,3 @@ const certificationCount = createResource({
|
||||
auto: true,
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
.apexcharts-legend {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
</div>
|
||||
<div class="overflow-y-auto">
|
||||
<SettingFields :fields="fields" :data="data.data" />
|
||||
<div class="flex flex-row-reverse mt-auto">
|
||||
<Button variant="solid" :loading="saveSettings.loading" @click="update">
|
||||
{{ __('Update') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row-reverse mt-auto">
|
||||
<Button variant="solid" :loading="saveSettings.loading" @click="update">
|
||||
{{ __('Update') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,16 +1,32 @@
|
||||
<template>
|
||||
<div class="flex flex-col min-h-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="text-xl font-semibold mb-5 text-ink-gray-9">
|
||||
{{ label }}
|
||||
<div class="flex flex-col min-h-0 text-base">
|
||||
<div class="flex items-center justify-between mb-5">
|
||||
<div class="flex flex-col space-y-2">
|
||||
<div class="text-xl font-semibold text-ink-gray-9">
|
||||
{{ label }}
|
||||
</div>
|
||||
<div class="text-xs text-ink-gray-5">
|
||||
{{ __(description) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-5">
|
||||
<div
|
||||
class="flex items-center space-x-1 text-ink-amber-3 border border-outline-amber-1 bg-surface-amber-1 rounded-lg px-2 py-1"
|
||||
v-if="saving"
|
||||
>
|
||||
<LoadingIndicator class="size-2" />
|
||||
<span class="text-xs">
|
||||
{{ __('saving...') }}
|
||||
</span>
|
||||
</div>
|
||||
<Button @click="() => showCategoryForm()">
|
||||
<template #prefix>
|
||||
<Plus v-if="!showForm" class="h-3 w-3 stroke-1.5" />
|
||||
<X v-else class="h-3 w-3 stroke-1.5" />
|
||||
</template>
|
||||
{{ showForm ? __('Close') : __('New') }}
|
||||
</Button>
|
||||
</div>
|
||||
<Button @click="() => showCategoryForm()">
|
||||
<template #prefix>
|
||||
<Plus v-if="!showForm" class="h-3 w-3 stroke-1.5" />
|
||||
<X v-else class="h-3 w-3 stroke-1.5" />
|
||||
</template>
|
||||
{{ showForm ? __('Close') : __('New') }}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -29,13 +45,39 @@
|
||||
</div>
|
||||
|
||||
<div class="overflow-y-scroll">
|
||||
<div class="text-base space-y-2">
|
||||
<FormControl
|
||||
:value="cat.category"
|
||||
type="text"
|
||||
v-for="cat in categories.data"
|
||||
@change.stop="(e) => update(cat.name, e.target.value)"
|
||||
/>
|
||||
<div class="divide-y space-y-2">
|
||||
<div
|
||||
v-for="(cat, index) in categories.data"
|
||||
:key="cat.name"
|
||||
class="pt-2"
|
||||
>
|
||||
<div
|
||||
v-if="editing?.name !== cat.name"
|
||||
class="flex items-center justify-between group text-sm"
|
||||
>
|
||||
<div @dblclick="allowEdit(cat, index)">
|
||||
{{ cat.category }}
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
theme="red"
|
||||
class="invisible group-hover:visible"
|
||||
@click="deleteCategory(cat.name)"
|
||||
>
|
||||
<template #icon>
|
||||
<Trash2 class="size-4 stroke-1.5 text-ink-red-4" />
|
||||
</template>
|
||||
</Button>
|
||||
</div>
|
||||
<FormControl
|
||||
v-else
|
||||
:ref="(el) => (editInputRef[index] = el)"
|
||||
v-model="editedValue"
|
||||
type="text"
|
||||
class="w-full"
|
||||
@keyup.enter="saveChanges(cat.name, editedValue)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -44,16 +86,22 @@
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
LoadingIndicator,
|
||||
createListResource,
|
||||
createResource,
|
||||
debounce,
|
||||
toast,
|
||||
} from 'frappe-ui'
|
||||
import { Plus, X } from 'lucide-vue-next'
|
||||
import { Plus, Trash2, X } from 'lucide-vue-next'
|
||||
import { ref } from 'vue'
|
||||
import { cleanError } from '@/utils'
|
||||
|
||||
const showForm = ref(false)
|
||||
const category = ref(null)
|
||||
const categoryInput = ref(null)
|
||||
const saving = ref(false)
|
||||
const editing = ref(null)
|
||||
const editedValue = ref('')
|
||||
const editInputRef = ref([])
|
||||
|
||||
const props = defineProps({
|
||||
label: {
|
||||
@@ -72,25 +120,20 @@ const categories = createListResource({
|
||||
auto: true,
|
||||
})
|
||||
|
||||
const newCategory = createResource({
|
||||
url: 'frappe.client.insert',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doc: {
|
||||
doctype: 'LMS Category',
|
||||
category: category.value,
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const addCategory = () => {
|
||||
newCategory.submit(
|
||||
{},
|
||||
categories.insert.submit(
|
||||
{
|
||||
category: category.value,
|
||||
},
|
||||
{
|
||||
onSuccess(data) {
|
||||
categories.reload()
|
||||
category.value = null
|
||||
showForm.value = false
|
||||
toast.success(__('Category added successfully'))
|
||||
},
|
||||
onError(err) {
|
||||
toast.error(__(cleanError(err.messages[0]) || 'Unable to add category'))
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -115,6 +158,7 @@ const updateCategory = createResource({
|
||||
})
|
||||
|
||||
const update = (name, value) => {
|
||||
saving.value = true
|
||||
updateCategory.submit(
|
||||
{
|
||||
name: name,
|
||||
@@ -122,9 +166,51 @@ const update = (name, value) => {
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
saving.value = false
|
||||
categories.reload()
|
||||
editing.value = null
|
||||
editedValue.value = ''
|
||||
toast.success(__('Category updated successfully'))
|
||||
},
|
||||
onError(err) {
|
||||
saving.value = false
|
||||
editing.value = null
|
||||
editedValue.value = ''
|
||||
toast.error(
|
||||
__(cleanError(err.messages[0]) || 'Unable to update category')
|
||||
)
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const deleteCategory = (name) => {
|
||||
saving.value = true
|
||||
categories.delete.submit(name, {
|
||||
onSuccess() {
|
||||
saving.value = false
|
||||
categories.reload()
|
||||
toast.success(__('Category deleted successfully'))
|
||||
},
|
||||
onError(err) {
|
||||
saving.value = false
|
||||
toast.error(
|
||||
__(cleanError(err.messages[0]) || 'Unable to delete category')
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const saveChanges = (name, value) => {
|
||||
saving.value = true
|
||||
update(name, value)
|
||||
}
|
||||
|
||||
const allowEdit = (cat, index) => {
|
||||
editing.value = cat
|
||||
editedValue.value = cat.category
|
||||
setTimeout(() => {
|
||||
editInputRef.value[index].$el.querySelector('input').focus()
|
||||
}, 0)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
v-if="parseInt(course.data.rating) > 0"
|
||||
class="flex items-center text-ink-gray-9"
|
||||
>
|
||||
<Star class="h-4 w-4 stroke-1.5 fill-orange-500 text-gray-50" />
|
||||
<Star class="size-4 stroke-1.5 fill-yellow-500 text-transparent" />
|
||||
<span class="ml-2">
|
||||
{{ course.data.rating }} {{ __('Rating') }}
|
||||
</span>
|
||||
|
||||
@@ -35,14 +35,14 @@
|
||||
<span class="text-ink-gray-7">
|
||||
{{ review.creation }}
|
||||
</span>
|
||||
<div class="flex mt-2">
|
||||
<div class="flex mt-2 space-x-1">
|
||||
<Star
|
||||
v-for="index in 5"
|
||||
class="h-5 w-5 text-ink-gray-1 rounded-sm mr-2"
|
||||
class="size-4 text-transparent rounded-sm"
|
||||
:class="
|
||||
index <= Math.ceil(review.rating)
|
||||
? 'fill-orange-500'
|
||||
: 'fill-gray-600'
|
||||
? 'fill-yellow-500'
|
||||
: 'fill-gray-300'
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
||||
160
frontend/src/components/EmailTemplates.vue
Normal file
160
frontend/src/components/EmailTemplates.vue
Normal file
@@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<div class="flex flex-col min-h-0 text-base">
|
||||
<div class="flex items-center justify-between mb-5">
|
||||
<div class="flex flex-col space-y-2">
|
||||
<div class="text-xl font-semibold text-ink-gray-9">
|
||||
{{ label }}
|
||||
</div>
|
||||
<div class="text-xs text-ink-gray-5">
|
||||
{{ __(description) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-5">
|
||||
<Button @click="openTemplateForm('new')">
|
||||
<template #prefix>
|
||||
<Plus class="h-3 w-3 stroke-1.5" />
|
||||
</template>
|
||||
{{ __('New') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="emailTemplates.data?.length" class="overflow-y-scroll">
|
||||
<ListView
|
||||
:columns="columns"
|
||||
:rows="emailTemplates.data"
|
||||
row-key="name"
|
||||
:options="{
|
||||
showTooltip: false,
|
||||
onRowClick: (row) => {
|
||||
openTemplateForm(row.name)
|
||||
},
|
||||
}"
|
||||
>
|
||||
<ListHeader
|
||||
class="mb-2 grid items-center space-x-4 rounded bg-surface-gray-2 p-2"
|
||||
>
|
||||
<ListHeaderItem :item="item" v-for="item in columns">
|
||||
<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 emailTemplates.data">
|
||||
<template #default="{ column, item }">
|
||||
<ListRowItem :item="row[column.key]" :align="column.align">
|
||||
<div class="leading-5 text-sm">
|
||||
{{ row[column.key] }}
|
||||
</div>
|
||||
</ListRowItem>
|
||||
</template>
|
||||
</ListRow>
|
||||
</ListRows>
|
||||
|
||||
<ListSelectBanner>
|
||||
<template #actions="{ unselectAll, selections }">
|
||||
<div class="flex gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
@click="removeTemplate(selections, unselectAll)"
|
||||
>
|
||||
<Trash2 class="h-4 w-4 stroke-1.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</ListSelectBanner>
|
||||
</ListView>
|
||||
</div>
|
||||
</div>
|
||||
<EmailTemplateModal
|
||||
v-model="showForm"
|
||||
v-model:emailTemplates="emailTemplates"
|
||||
:templateID="selectedTemplate"
|
||||
/>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Button,
|
||||
call,
|
||||
createListResource,
|
||||
ListView,
|
||||
ListHeader,
|
||||
ListHeaderItem,
|
||||
ListSelectBanner,
|
||||
ListRows,
|
||||
ListRow,
|
||||
ListRowItem,
|
||||
toast,
|
||||
} from 'frappe-ui'
|
||||
import { computed, ref } from 'vue'
|
||||
import { Plus, Trash2 } from 'lucide-vue-next'
|
||||
import EmailTemplateModal from '@/components/Modals/EmailTemplateModal.vue'
|
||||
|
||||
const props = defineProps({
|
||||
label: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const showForm = ref(false)
|
||||
const readOnlyMode = window.read_only_mode
|
||||
const selectedTemplate = ref(null)
|
||||
|
||||
const emailTemplates = createListResource({
|
||||
doctype: 'Email Template',
|
||||
fields: ['name', 'subject', 'use_html', 'response', 'response_html'],
|
||||
auto: true,
|
||||
orderBy: 'modified desc',
|
||||
cache: 'email-templates',
|
||||
})
|
||||
|
||||
const removeTemplate = (selections, unselectAll) => {
|
||||
call('lms.lms.api.delete_documents', {
|
||||
doctype: 'Email Template',
|
||||
documents: Array.from(selections),
|
||||
})
|
||||
.then(() => {
|
||||
emailTemplates.reload()
|
||||
toast.success(__('Email Templates deleted successfully'))
|
||||
unselectAll()
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.error(
|
||||
cleanError(err.messages[0]) || __('Error deleting email templates')
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const openTemplateForm = (templateID) => {
|
||||
if (readOnlyMode) {
|
||||
return
|
||||
}
|
||||
selectedTemplate.value = templateID
|
||||
showForm.value = true
|
||||
}
|
||||
|
||||
const columns = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: 'Name',
|
||||
key: 'name',
|
||||
width: '20rem',
|
||||
},
|
||||
{
|
||||
label: 'Subject',
|
||||
key: 'subject',
|
||||
width: '25rem',
|
||||
},
|
||||
]
|
||||
})
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex min-h-0 flex-col text-base">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div>
|
||||
<div class="text-xl font-semibold mb-1 text-ink-gray-9">
|
||||
@@ -39,25 +39,27 @@
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div class="divide-y">
|
||||
<div
|
||||
v-for="evaluator in evaluators.data"
|
||||
@click="openProfile(evaluator.username)"
|
||||
class="cursor-pointer"
|
||||
>
|
||||
<div class="flex items-center justify-between py-3">
|
||||
<div class="flex items-center space-x-3">
|
||||
<Avatar
|
||||
:image="evaluator.user_image"
|
||||
:label="evaluator.full_name"
|
||||
size="lg"
|
||||
/>
|
||||
<div>
|
||||
<div class="text-base font-semibold text-ink-gray-9">
|
||||
{{ evaluator.full_name }}
|
||||
</div>
|
||||
<div class="text-xs text-ink-gray-5">
|
||||
{{ evaluator.evaluator }}
|
||||
<div class="overflow-y-scroll">
|
||||
<div class="divide-y">
|
||||
<div
|
||||
v-for="evaluator in evaluators.data"
|
||||
@click="openProfile(evaluator.username)"
|
||||
class="cursor-pointer"
|
||||
>
|
||||
<div class="flex items-center justify-between py-3">
|
||||
<div class="flex items-center space-x-3">
|
||||
<Avatar
|
||||
:image="evaluator.user_image"
|
||||
:label="evaluator.full_name"
|
||||
size="lg"
|
||||
/>
|
||||
<div>
|
||||
<div class="text-base font-semibold text-ink-gray-9">
|
||||
{{ evaluator.full_name }}
|
||||
</div>
|
||||
<div class="text-xs text-ink-gray-5">
|
||||
{{ evaluator.evaluator }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,60 +1,55 @@
|
||||
<template>
|
||||
<div class="flex h-full flex-col">
|
||||
<div class="flex h-full flex-col relative">
|
||||
<div class="h-full pb-10" id="scrollContainer">
|
||||
<slot />
|
||||
</div>
|
||||
<div
|
||||
v-if="sidebarSettings.data"
|
||||
class="fixed flex items-center justify-around border-t border-outline-gray-2 bottom-0 z-10 w-full bg-surface-white standalone:pb-4"
|
||||
:style="{
|
||||
gridTemplateColumns: `repeat(${
|
||||
sidebarLinks.length + 1
|
||||
}, minmax(0, 1fr))`,
|
||||
}"
|
||||
>
|
||||
<button
|
||||
v-for="tab in sidebarLinks"
|
||||
:key="tab.label"
|
||||
:class="isVisible(tab) ? 'block' : 'hidden'"
|
||||
class="flex flex-col items-center justify-center py-3 transition active:scale-95"
|
||||
@click="handleClick(tab)"
|
||||
|
||||
<div class="relative z-20">
|
||||
<!-- Dropdown menu -->
|
||||
<div
|
||||
class="fixed bottom-16 right-2 w-[80%] rounded-md bg-surface-white text-base p-5 space-y-4 shadow-md"
|
||||
v-if="showMenu"
|
||||
ref="menu"
|
||||
>
|
||||
<component
|
||||
:is="icons[tab.icon]"
|
||||
class="h-6 w-6 stroke-1.5"
|
||||
:class="[isActive(tab) ? 'text-ink-gray-9' : 'text-ink-gray-5']"
|
||||
/>
|
||||
</button>
|
||||
<Popover
|
||||
trigger="hover"
|
||||
popoverClass="bottom-28 mx-2"
|
||||
placement="top-start"
|
||||
<div
|
||||
v-for="link in otherLinks"
|
||||
:key="link.label"
|
||||
class="flex items-center space-x-2 cursor-pointer"
|
||||
@click="handleClick(link)"
|
||||
>
|
||||
<component
|
||||
:is="icons[link.icon]"
|
||||
class="h-4 w-4 stroke-1.5 text-ink-gray-5"
|
||||
/>
|
||||
<div>{{ link.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fixed menu -->
|
||||
<div
|
||||
v-if="sidebarSettings.data"
|
||||
class="fixed bottom-0 left-0 w-full flex items-center justify-around border-t border-outline-gray-2 bg-surface-white standalone:pb-4 z-10"
|
||||
>
|
||||
<template #target>
|
||||
<button
|
||||
v-for="tab in sidebarLinks"
|
||||
:key="tab.label"
|
||||
:class="isVisible(tab) ? 'block' : 'hidden'"
|
||||
class="flex flex-col items-center justify-center py-3 transition active:scale-95"
|
||||
@click="handleClick(tab)"
|
||||
>
|
||||
<component
|
||||
:is="icons[tab.icon]"
|
||||
class="h-6 w-6 stroke-1.5"
|
||||
:class="[isActive(tab) ? 'text-ink-gray-9' : 'text-ink-gray-5']"
|
||||
/>
|
||||
</button>
|
||||
<button @click="toggleMenu">
|
||||
<component
|
||||
:is="icons['List']"
|
||||
class="h-6 w-6 stroke-1.5 text-ink-gray-5"
|
||||
/>
|
||||
</template>
|
||||
<template #body-main>
|
||||
<div class="text-base p-5 space-y-4">
|
||||
<div
|
||||
v-for="link in otherLinks"
|
||||
:key="link.label"
|
||||
class="flex items-center space-x-2"
|
||||
@click="handleClick(link)"
|
||||
>
|
||||
<component
|
||||
:is="icons[link.icon]"
|
||||
class="h-4 w-4 stroke-1.5 text-ink-gray-5"
|
||||
/>
|
||||
<div>
|
||||
{{ link.label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -64,7 +59,6 @@ import { useRouter } from 'vue-router'
|
||||
import { watch, ref, onMounted } from 'vue'
|
||||
import { sessionStore } from '@/stores/session'
|
||||
import { usersStore } from '@/stores/user'
|
||||
import { Popover } from 'frappe-ui'
|
||||
import * as icons from 'lucide-vue-next'
|
||||
|
||||
const { logout, user, sidebarSettings } = sessionStore()
|
||||
@@ -73,26 +67,47 @@ const router = useRouter()
|
||||
let { userResource } = usersStore()
|
||||
const sidebarLinks = ref(getSidebarLinks())
|
||||
const otherLinks = ref([])
|
||||
const showMenu = ref(false)
|
||||
const menu = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
sidebarSettings.reload(
|
||||
{},
|
||||
{
|
||||
onSuccess(data) {
|
||||
Object.keys(data).forEach((key) => {
|
||||
if (!parseInt(data[key])) {
|
||||
sidebarLinks.value = sidebarLinks.value.filter(
|
||||
(link) => link.label.toLowerCase().split(' ').join('_') !== key
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
filterLinksToShow(data)
|
||||
addOtherLinks()
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const handleOutsideClick = (e) => {
|
||||
if (menu.value && !menu.value.contains(e.target)) {
|
||||
showMenu.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(showMenu, (val) => {
|
||||
if (val) {
|
||||
setTimeout(() => {
|
||||
document.addEventListener('click', handleOutsideClick)
|
||||
}, 0)
|
||||
} else {
|
||||
document.removeEventListener('click', handleOutsideClick)
|
||||
}
|
||||
})
|
||||
|
||||
const filterLinksToShow = (data) => {
|
||||
Object.keys(data).forEach((key) => {
|
||||
if (!parseInt(data[key])) {
|
||||
sidebarLinks.value = sidebarLinks.value.filter(
|
||||
(link) => link.label.toLowerCase().split(' ').join('_') !== key
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const addOtherLinks = () => {
|
||||
if (user) {
|
||||
otherLinks.value.push({
|
||||
@@ -122,6 +137,7 @@ watch(userResource, () => {
|
||||
(userResource.data.is_moderator || userResource.data.is_instructor)
|
||||
) {
|
||||
addQuizzes()
|
||||
addAssignments()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -133,6 +149,14 @@ const addQuizzes = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const addAssignments = () => {
|
||||
otherLinks.value.push({
|
||||
label: 'Assignments',
|
||||
icon: 'Pencil',
|
||||
to: 'Assignments',
|
||||
})
|
||||
}
|
||||
|
||||
let isActive = (tab) => {
|
||||
return tab.activeFor?.includes(router.currentRoute.value.name)
|
||||
}
|
||||
@@ -158,4 +182,8 @@ const isVisible = (tab) => {
|
||||
else if (tab.label == 'Log out') return isLoggedIn
|
||||
else return true
|
||||
}
|
||||
|
||||
const toggleMenu = () => {
|
||||
showMenu.value = !showMenu.value
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}"
|
||||
>
|
||||
<template #body>
|
||||
<div class="p-5 text-base max-h-[75vh] overflow-y-auto">
|
||||
<div class="p-5 text-base">
|
||||
<div class="text-lg text-ink-gray-9 font-semibold mb-5">
|
||||
{{
|
||||
assignmentID === 'new'
|
||||
@@ -14,7 +14,7 @@
|
||||
: __('Edit Assignment')
|
||||
}}
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-4 max-h-[75vh] overflow-y-auto">
|
||||
<FormControl
|
||||
v-model="assignment.title"
|
||||
:label="__('Title')"
|
||||
|
||||
192
frontend/src/components/Modals/EmailTemplateModal.vue
Normal file
192
frontend/src/components/Modals/EmailTemplateModal.vue
Normal file
@@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<Dialog
|
||||
v-model="show"
|
||||
:options="{
|
||||
title:
|
||||
templateID == 'new'
|
||||
? __('New Email Template')
|
||||
: __('Edit Email Template'),
|
||||
size: 'lg',
|
||||
actions: [
|
||||
{
|
||||
label: __('Save'),
|
||||
variant: 'solid',
|
||||
onClick: ({ close }) => {
|
||||
saveTemplate(close)
|
||||
},
|
||||
},
|
||||
],
|
||||
}"
|
||||
>
|
||||
<template #body-content>
|
||||
<div class="space-y-4">
|
||||
<FormControl
|
||||
:label="__('Name')"
|
||||
v-model="template.name"
|
||||
type="text"
|
||||
:required="true"
|
||||
:placeholder="__('Batch Enrollment Confirmation')"
|
||||
/>
|
||||
<FormControl
|
||||
:label="__('Subject')"
|
||||
v-model="template.subject"
|
||||
type="text"
|
||||
:required="true"
|
||||
:placeholder="__('Your enrollment in {{ batch_name }} is confirmed')"
|
||||
/>
|
||||
<FormControl
|
||||
:label="__('Use HTML')"
|
||||
v-model="template.use_html"
|
||||
type="checkbox"
|
||||
/>
|
||||
<FormControl
|
||||
v-if="template.use_html"
|
||||
:label="__('Content')"
|
||||
v-model="template.response_html"
|
||||
type="textarea"
|
||||
:required="true"
|
||||
:rows="10"
|
||||
:placeholder="
|
||||
__(
|
||||
'<p>Dear {{ member_name }},</p>\n\n<p>You have been enrolled in our upcoming batch {{ batch_name }}.</p>\n\n<p>Thanks,</p>\n<p>Frappe Learning</p>'
|
||||
)
|
||||
"
|
||||
/>
|
||||
<div v-else>
|
||||
<div class="text-xs text-ink-gray-5 mb-2">
|
||||
{{ __('Content') }}
|
||||
<span class="text-ink-red-3">*</span>
|
||||
</div>
|
||||
<TextEditor
|
||||
:content="template.response"
|
||||
@change="(val) => (template.response = val)"
|
||||
:editable="true"
|
||||
:fixedMenu="true"
|
||||
:placeholder="
|
||||
__(
|
||||
'Dear {{ member_name }},\n\nYou have been enrolled in our upcoming batch {{ batch_name }}.\n\nThanks,\nFrappe Learning'
|
||||
)
|
||||
"
|
||||
editorClass="prose-sm max-w-none border-b border-x bg-surface-gray-2 rounded-b-md py-1 px-2 min-h-[7rem] max-h-[18rem] overflow-y-auto"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { call, Dialog, FormControl, TextEditor, toast } from 'frappe-ui'
|
||||
import { reactive, watch } from 'vue'
|
||||
import { cleanError } from '@/utils'
|
||||
|
||||
const props = defineProps({
|
||||
templateID: {
|
||||
type: String,
|
||||
default: 'new',
|
||||
},
|
||||
})
|
||||
|
||||
const show = defineModel()
|
||||
const emailTemplates = defineModel('emailTemplates')
|
||||
const template = reactive({
|
||||
name: '',
|
||||
subject: '',
|
||||
use_html: false,
|
||||
response: '',
|
||||
response_html: '',
|
||||
})
|
||||
|
||||
const saveTemplate = (close) => {
|
||||
if (props.templateID == 'new') {
|
||||
createNewTemplate(close)
|
||||
} else {
|
||||
updateTemplate(close)
|
||||
}
|
||||
}
|
||||
|
||||
const createNewTemplate = (close) => {
|
||||
emailTemplates.value.insert.submit(
|
||||
{
|
||||
__newname: template.name,
|
||||
...template,
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
emailTemplates.value.reload()
|
||||
refreshForm(close)
|
||||
toast.success(__('Email Template created successfully'))
|
||||
},
|
||||
onError(err) {
|
||||
refreshForm(close)
|
||||
toast.error(
|
||||
cleanError(err.messages[0]) || __('Error creating email template')
|
||||
)
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const updateTemplate = async (close) => {
|
||||
if (props.templateID != template.name) {
|
||||
await renameDoc()
|
||||
}
|
||||
setValue(close)
|
||||
}
|
||||
|
||||
const setValue = (close) => {
|
||||
emailTemplates.value.setValue.submit(
|
||||
{
|
||||
...template,
|
||||
name: template.name,
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
emailTemplates.value.reload()
|
||||
refreshForm(close)
|
||||
toast.success(__('Email Template updated successfully'))
|
||||
},
|
||||
onError(err) {
|
||||
refreshForm(close)
|
||||
toast.error(
|
||||
cleanError(err.messages[0]) || __('Error updating email template')
|
||||
)
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const renameDoc = async () => {
|
||||
await call('frappe.client.rename_doc', {
|
||||
doctype: 'Email Template',
|
||||
old_name: props.templateID,
|
||||
new_name: template.name,
|
||||
})
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.templateID,
|
||||
(val) => {
|
||||
if (val !== 'new') {
|
||||
emailTemplates.value?.data.forEach((row) => {
|
||||
if (row.name === val) {
|
||||
template.name = row.name
|
||||
template.subject = row.subject
|
||||
template.use_html = row.use_html
|
||||
template.response = row.response
|
||||
template.response_html = row.response_html
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
{ flush: 'post' }
|
||||
)
|
||||
|
||||
const refreshForm = (close) => {
|
||||
close()
|
||||
template.name = ''
|
||||
template.subject = ''
|
||||
template.use_html = false
|
||||
template.response = ''
|
||||
template.response_html = ''
|
||||
}
|
||||
</script>
|
||||
@@ -66,7 +66,7 @@
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Dialog, createResource, Select, FormControl } from 'frappe-ui'
|
||||
import { Dialog, createResource, Select, FormControl, toast } from 'frappe-ui'
|
||||
import { reactive, watch, inject } from 'vue'
|
||||
import { formatTime } from '@/utils/'
|
||||
|
||||
@@ -90,7 +90,7 @@ const props = defineProps({
|
||||
},
|
||||
})
|
||||
|
||||
let evaluation = reactive({
|
||||
const evaluation = reactive({
|
||||
course: '',
|
||||
date: '',
|
||||
start_time: '',
|
||||
@@ -139,7 +139,7 @@ function submitEvaluation(close) {
|
||||
close()
|
||||
},
|
||||
onError(err) {
|
||||
let message = err.messages?.[0] || err
|
||||
const message = err.messages?.[0] || err
|
||||
let unavailabilityMessage
|
||||
|
||||
if (typeof message === 'string') {
|
||||
@@ -148,13 +148,13 @@ function submitEvaluation(close) {
|
||||
unavailabilityMessage = false
|
||||
}
|
||||
|
||||
toast.warning(__('Evaluator is unavailable'))
|
||||
toast.warning(__(unavailabilityMessage || 'Evaluator is unavailable'))
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const getCourses = () => {
|
||||
let courses = []
|
||||
const courses = []
|
||||
for (const course of props.courses) {
|
||||
if (course.evaluator) {
|
||||
courses.push({
|
||||
@@ -164,7 +164,7 @@ const getCourses = () => {
|
||||
}
|
||||
}
|
||||
|
||||
if (courses.length == 1) {
|
||||
if (courses.length === 1) {
|
||||
evaluation.course = courses[0].value
|
||||
}
|
||||
|
||||
|
||||
115
frontend/src/components/Modals/FeedbackModal.vue
Normal file
115
frontend/src/components/Modals/FeedbackModal.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<Dialog
|
||||
v-model="show"
|
||||
:options="{
|
||||
size: '4xl',
|
||||
}"
|
||||
>
|
||||
<template #body>
|
||||
<div class="p-5 min-h-[300px]">
|
||||
<div class="text-lg font-semibold mb-4">
|
||||
{{ __('Training Feedback') }}
|
||||
</div>
|
||||
<ListView
|
||||
:columns="feedbackColumns"
|
||||
:rows="feedbackList"
|
||||
row-key="name"
|
||||
:options="{
|
||||
showTooltip: false,
|
||||
rowHeight: 'h-16',
|
||||
selectable: false,
|
||||
}"
|
||||
>
|
||||
<ListHeader
|
||||
class="mb-2 grid items-center space-x-4 rounded bg-surface-gray-2 p-2"
|
||||
></ListHeader>
|
||||
<ListRows>
|
||||
<ListRow
|
||||
:row="row"
|
||||
v-for="row in feedbackList"
|
||||
class="group feedback-list"
|
||||
>
|
||||
<template #default="{ column, item }">
|
||||
<ListRowItem
|
||||
:item="row[column.key]"
|
||||
:align="column.align"
|
||||
class="text-sm"
|
||||
>
|
||||
<template #prefix>
|
||||
<div v-if="column.key == 'member_name'">
|
||||
<Avatar
|
||||
class="flex"
|
||||
:image="row['member_image']"
|
||||
:label="item"
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="ratingKeys.includes(column.key)">
|
||||
<Rating v-model="row[column.key]" :readonly="true" />
|
||||
</div>
|
||||
<div v-else class="leading-5">
|
||||
{{ row[column.key] }}
|
||||
</div>
|
||||
</ListRowItem>
|
||||
</template>
|
||||
</ListRow>
|
||||
</ListRows>
|
||||
</ListView>
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Dialog,
|
||||
ListView,
|
||||
Avatar,
|
||||
ListHeader,
|
||||
ListRows,
|
||||
ListRow,
|
||||
ListRowItem,
|
||||
Rating,
|
||||
} from 'frappe-ui'
|
||||
import { reactive, computed } from 'vue'
|
||||
|
||||
const show = defineModel()
|
||||
const ratingKeys = ['content', 'instructors', 'value']
|
||||
|
||||
const props = defineProps({
|
||||
feedbackList: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const feedbackColumns = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: 'Member',
|
||||
key: 'member_name',
|
||||
width: '10rem',
|
||||
},
|
||||
{
|
||||
label: 'Feedback',
|
||||
key: 'feedback',
|
||||
width: '15rem',
|
||||
},
|
||||
{
|
||||
label: 'Content',
|
||||
key: 'content',
|
||||
width: '9rem',
|
||||
},
|
||||
{
|
||||
label: 'Instructors',
|
||||
key: 'instructors',
|
||||
width: '9rem',
|
||||
},
|
||||
{
|
||||
label: 'Value',
|
||||
key: 'value',
|
||||
width: '9rem',
|
||||
},
|
||||
]
|
||||
})
|
||||
</script>
|
||||
@@ -15,26 +15,20 @@
|
||||
>
|
||||
<template #body-content>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div>
|
||||
<div class="mb-1.5 text-sm text-ink-gray-5">
|
||||
{{ __('Rating') }}
|
||||
</div>
|
||||
<Rating v-model="review.rating" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-1.5 text-sm text-ink-gray-5">
|
||||
{{ __('Review') }}
|
||||
</div>
|
||||
<Textarea type="text" size="md" rows="5" v-model="review.review" />
|
||||
</div>
|
||||
<Rating v-model="review.rating" :label="__('Rating')" />
|
||||
<FormControl
|
||||
:label="__('Review')"
|
||||
type="textarea"
|
||||
v-model="review.review"
|
||||
:rows="5"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Dialog, Textarea, createResource, toast } from 'frappe-ui'
|
||||
import { Dialog, FormControl, createResource, toast, Rating } from 'frappe-ui'
|
||||
import { reactive } from 'vue'
|
||||
import Rating from '@/components/Controls/Rating.vue'
|
||||
|
||||
const show = defineModel()
|
||||
const reviews = defineModel('reloadReviews')
|
||||
|
||||
@@ -51,6 +51,11 @@
|
||||
:label="activeTab.label"
|
||||
:description="activeTab.description"
|
||||
/>
|
||||
<EmailTemplates
|
||||
v-else-if="activeTab.label === 'Email Templates'"
|
||||
:label="activeTab.label"
|
||||
:description="activeTab.description"
|
||||
/>
|
||||
<PaymentSettings
|
||||
v-else-if="activeTab.label === 'Payment Gateway'"
|
||||
:label="activeTab.label"
|
||||
@@ -86,6 +91,7 @@ import SidebarLink from '@/components/SidebarLink.vue'
|
||||
import Members from '@/components/Members.vue'
|
||||
import Evaluators from '@/components/Evaluators.vue'
|
||||
import Categories from '@/components/Categories.vue'
|
||||
import EmailTemplates from '@/components/EmailTemplates.vue'
|
||||
import BrandSettings from '@/components/BrandSettings.vue'
|
||||
import PaymentSettings from '@/components/PaymentSettings.vue'
|
||||
|
||||
@@ -122,7 +128,7 @@ const tabsStructure = computed(() => {
|
||||
label: 'Enable Learning Paths',
|
||||
name: 'enable_learning_paths',
|
||||
description:
|
||||
'This will enforce students to go through programs assigned to them in the correct order.',
|
||||
'This will ensure students follow the assigned programs in order.',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
@@ -139,11 +145,26 @@ const tabsStructure = computed(() => {
|
||||
'If enabled, it sends google calendar invite to the student for evaluations.',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
type: 'Column Break',
|
||||
},
|
||||
{
|
||||
label: 'Batch Confirmation Template',
|
||||
name: 'batch_confirmation_template',
|
||||
doctype: 'Email Template',
|
||||
type: 'Link',
|
||||
},
|
||||
{
|
||||
label: 'Certification Template',
|
||||
name: 'certification_template',
|
||||
doctype: 'Email Template',
|
||||
type: 'Link',
|
||||
},
|
||||
{
|
||||
label: 'Unsplash Access Key',
|
||||
name: 'unsplash_access_key',
|
||||
description:
|
||||
'Optional. If this is set, students can pick a cover image from the unsplash library for their profile page. https://unsplash.com/documentation#getting-started.',
|
||||
'Allows users to pick a profile cover image from Unsplash. https://unsplash.com/documentation#getting-started.',
|
||||
type: 'password',
|
||||
},
|
||||
],
|
||||
@@ -160,6 +181,12 @@ const tabsStructure = computed(() => {
|
||||
description:
|
||||
'Configure the payment gateway and other payment related settings',
|
||||
fields: [
|
||||
{
|
||||
label: 'Default Currency',
|
||||
name: 'default_currency',
|
||||
type: 'Link',
|
||||
doctype: 'Currency',
|
||||
},
|
||||
{
|
||||
label: 'Payment Gateway',
|
||||
name: 'payment_gateway',
|
||||
@@ -167,10 +194,7 @@ const tabsStructure = computed(() => {
|
||||
doctype: 'Payment Gateway',
|
||||
},
|
||||
{
|
||||
label: 'Default Currency',
|
||||
name: 'default_currency',
|
||||
type: 'Link',
|
||||
doctype: 'Currency',
|
||||
type: 'Column Break',
|
||||
},
|
||||
{
|
||||
label: 'Apply GST for India',
|
||||
@@ -207,9 +231,14 @@ const tabsStructure = computed(() => {
|
||||
},
|
||||
{
|
||||
label: 'Categories',
|
||||
description: 'Manage the members of your learning system',
|
||||
description: 'Double click to edit the category',
|
||||
icon: 'Network',
|
||||
},
|
||||
{
|
||||
label: 'Email Templates',
|
||||
description: 'Manage the email templates for your learning system',
|
||||
icon: 'MailPlus',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -235,28 +264,6 @@ const tabsStructure = computed(() => {
|
||||
name: 'favicon',
|
||||
type: 'Upload',
|
||||
},
|
||||
{
|
||||
label: 'Footer Logo',
|
||||
name: 'footer_logo',
|
||||
type: 'Upload',
|
||||
},
|
||||
{
|
||||
label: 'Address',
|
||||
name: 'address',
|
||||
type: 'textarea',
|
||||
rows: 2,
|
||||
},
|
||||
{
|
||||
label: 'Footer "Powered By"',
|
||||
name: 'footer_powered',
|
||||
type: 'textarea',
|
||||
rows: 4,
|
||||
},
|
||||
{
|
||||
label: 'Copyright',
|
||||
name: 'copyright',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -299,24 +306,6 @@ const tabsStructure = computed(() => {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Email Templates',
|
||||
icon: 'MailPlus',
|
||||
fields: [
|
||||
{
|
||||
label: 'Batch Confirmation Template',
|
||||
name: 'batch_confirmation_template',
|
||||
doctype: 'Email Template',
|
||||
type: 'Link',
|
||||
},
|
||||
{
|
||||
label: 'Certification Template',
|
||||
name: 'certification_template',
|
||||
doctype: 'Email Template',
|
||||
type: 'Link',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Signup',
|
||||
icon: 'LogIn',
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
/> -->
|
||||
</div>
|
||||
<div class="overflow-y-scroll">
|
||||
<div class="flex space-x-4">
|
||||
<SettingFields :fields="fields" :data="data.doc" class="w-1/2" />
|
||||
<div class="flex flex-col divide-y">
|
||||
<SettingFields :fields="fields" :data="data.doc" />
|
||||
<SettingFields
|
||||
v-if="paymentGateway.data"
|
||||
:fields="paymentGateway.data.fields"
|
||||
:data="paymentGateway.data.data"
|
||||
class="w-1/2"
|
||||
class="pt-5 my-0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,9 +60,28 @@ const paymentGateway = createResource({
|
||||
payment_gateway: props.data.doc.payment_gateway,
|
||||
}
|
||||
},
|
||||
transform(data) {
|
||||
arrangeFields(data.fields)
|
||||
return data
|
||||
},
|
||||
auto: true,
|
||||
})
|
||||
|
||||
const arrangeFields = (fields) => {
|
||||
fields = fields.sort((a, b) => {
|
||||
if (a.type === 'Upload' && b.type !== 'Upload') {
|
||||
return 1
|
||||
} else if (a.type !== 'Upload' && b.type === 'Upload') {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
|
||||
fields.splice(3, 0, {
|
||||
type: 'Column Break',
|
||||
})
|
||||
}
|
||||
|
||||
const saveSettings = createResource({
|
||||
url: 'frappe.client.set_value',
|
||||
makeParams(values) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div v-for="(column, index) in columns" :key="index">
|
||||
<div
|
||||
class="flex flex-col space-y-5"
|
||||
:class="columns.length > 1 ? 'w-72' : 'w-full'"
|
||||
:class="columns.length > 1 ? 'w-[21rem]' : 'w-1/2'"
|
||||
>
|
||||
<div v-for="field in column">
|
||||
<Link
|
||||
@@ -14,6 +14,7 @@
|
||||
v-model="data[field.name]"
|
||||
:doctype="field.doctype"
|
||||
:label="__(field.label)"
|
||||
:description="__(field.description)"
|
||||
/>
|
||||
|
||||
<div v-else-if="field.type == 'Code'">
|
||||
@@ -54,11 +55,11 @@
|
||||
<div v-else>
|
||||
<div class="flex items-center text-sm space-x-2">
|
||||
<div
|
||||
class="flex items-center justify-center rounded border border-outline-gray-modals bg-white w-[10rem] py-2"
|
||||
class="flex items-center justify-center rounded border border-outline-gray-1 bg-surface-gray-2 px-20 py-5"
|
||||
>
|
||||
<img
|
||||
:src="data[field.name]?.file_url || data[field.name]"
|
||||
class="w-[80%] rounded"
|
||||
class="size-6 rounded"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col flex-wrap">
|
||||
|
||||
@@ -88,56 +88,61 @@
|
||||
:scrollToBottom="false"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="tab.label == 'Feedback'">
|
||||
<BatchFeedback :batch="batch.data.name" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Tabs>
|
||||
</div>
|
||||
<div class="p-5">
|
||||
<div class="text-ink-gray-7 font-semibold mb-4">
|
||||
{{ __('About this batch') }}:
|
||||
</div>
|
||||
<div
|
||||
v-html="batch.data.description"
|
||||
class="leading-5 mb-4 text-ink-gray-7"
|
||||
></div>
|
||||
|
||||
<div class="flex items-center avatar-group overlap mb-5">
|
||||
<div
|
||||
class="h-6 mr-1"
|
||||
:class="{
|
||||
'avatar-group overlap': batch.data.instructors.length > 1,
|
||||
}"
|
||||
>
|
||||
<UserAvatar
|
||||
v-for="instructor in batch.data.instructors"
|
||||
:user="instructor"
|
||||
/>
|
||||
<div class="mb-10">
|
||||
<div class="text-ink-gray-7 font-semibold mb-2">
|
||||
{{ __('About this batch') }}
|
||||
</div>
|
||||
<div
|
||||
v-html="batch.data.description"
|
||||
class="leading-5 mb-4 text-ink-gray-7"
|
||||
></div>
|
||||
|
||||
<div class="flex items-center avatar-group overlap mb-5">
|
||||
<div
|
||||
class="h-6 mr-1"
|
||||
:class="{
|
||||
'avatar-group overlap': batch.data.instructors.length > 1,
|
||||
}"
|
||||
>
|
||||
<UserAvatar
|
||||
v-for="instructor in batch.data.instructors"
|
||||
:user="instructor"
|
||||
/>
|
||||
</div>
|
||||
<CourseInstructors :instructors="batch.data.instructors" />
|
||||
</div>
|
||||
<DateRange
|
||||
:startDate="batch.data.start_date"
|
||||
:endDate="batch.data.end_date"
|
||||
class="mb-3"
|
||||
/>
|
||||
<div class="flex items-center mb-4 text-ink-gray-7">
|
||||
<Clock class="h-4 w-4 stroke-1.5 mr-2" />
|
||||
<span>
|
||||
{{ formatTime(batch.data.start_time) }} -
|
||||
{{ formatTime(batch.data.end_time) }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="batch.data.timezone"
|
||||
class="flex items-center mb-4 text-ink-gray-7"
|
||||
>
|
||||
<Globe class="h-4 w-4 stroke-1.5 mr-2" />
|
||||
<span>
|
||||
{{ batch.data.timezone }}
|
||||
</span>
|
||||
</div>
|
||||
<CourseInstructors :instructors="batch.data.instructors" />
|
||||
</div>
|
||||
<DateRange
|
||||
:startDate="batch.data.start_date"
|
||||
:endDate="batch.data.end_date"
|
||||
class="mb-3"
|
||||
/>
|
||||
<div class="flex items-center mb-4 text-ink-gray-7">
|
||||
<Clock class="h-4 w-4 stroke-1.5 mr-2" />
|
||||
<span>
|
||||
{{ formatTime(batch.data.start_time) }} -
|
||||
{{ formatTime(batch.data.end_time) }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="batch.data.timezone"
|
||||
class="flex items-center mb-4 text-ink-gray-7"
|
||||
>
|
||||
<Globe class="h-4 w-4 stroke-1.5 mr-2" />
|
||||
<span>
|
||||
{{ batch.data.timezone }}
|
||||
</span>
|
||||
<div v-if="dayjs().isSameOrAfter(dayjs(batch.data.start_date))">
|
||||
<div class="text-ink-gray-7 font-semibold mb-2">
|
||||
{{ __('Feedback') }}
|
||||
</div>
|
||||
<BatchFeedback :batch="batch.data?.name" />
|
||||
</div>
|
||||
</div>
|
||||
<AnnouncementModal
|
||||
@@ -234,6 +239,7 @@ import Discussions from '@/components/Discussions.vue'
|
||||
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'
|
||||
|
||||
const user = inject('$user')
|
||||
const showAnnouncementModal = ref(false)
|
||||
@@ -277,11 +283,6 @@ const tabs = computed(() => {
|
||||
label: 'Discussions',
|
||||
icon: MessageCircle,
|
||||
})
|
||||
|
||||
batchTabs.push({
|
||||
label: 'Feedback',
|
||||
icon: ClipboardPen,
|
||||
})
|
||||
return batchTabs
|
||||
})
|
||||
|
||||
|
||||
@@ -37,14 +37,7 @@
|
||||
<BatchOverlay :batch="batch" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="grid lg:grid-cols-[60%,20%] gap-4 lg:gap-20 mt-10">
|
||||
<div class="order-2 lg:order-none">
|
||||
|
||||
</div>
|
||||
<div class="order-1 lg:order-none">
|
||||
<BatchOverlay :batch="batch" />
|
||||
</div>
|
||||
</div> -->
|
||||
<BatchOverlay :batch="batch" class="md:hidden mt-5" />
|
||||
<div v-if="batch.data.courses.length">
|
||||
<div class="flex items-center mt-10">
|
||||
<div class="text-2xl font-semibold">
|
||||
|
||||
@@ -153,6 +153,11 @@
|
||||
doctype="Email Template"
|
||||
:label="__('Email Template')"
|
||||
v-model="batch.confirmation_email_template"
|
||||
:onCreate="
|
||||
(value, close) => {
|
||||
openSettings('Email Templates', close)
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-5">
|
||||
|
||||
@@ -20,14 +20,12 @@
|
||||
</header>
|
||||
<div class="p-5 pb-10">
|
||||
<div
|
||||
v-if="batchCount"
|
||||
class="flex flex-col lg:flex-row space-y-4 lg:space-y-0 lg:items-center justify-between mb-5"
|
||||
>
|
||||
<div class="text-lg text-ink-gray-9 font-semibold">
|
||||
{{ __('All Batches') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="batches.data?.length || batchCount"
|
||||
class="flex flex-col space-y-2 lg:space-y-0 lg:flex-row lg:items-center lg:space-x-4"
|
||||
>
|
||||
<TabButtons
|
||||
@@ -115,12 +113,10 @@ const is_student = computed(() => user.data?.is_student)
|
||||
const currentTab = ref(is_student.value ? 'All' : 'Upcoming')
|
||||
const orderBy = ref('start_date')
|
||||
const readOnlyMode = window.read_only_mode
|
||||
const batchCount = ref(0)
|
||||
|
||||
onMounted(() => {
|
||||
setFiltersFromQuery()
|
||||
updateBatches()
|
||||
getBatchCount()
|
||||
categories.value = [
|
||||
{
|
||||
label: '',
|
||||
@@ -298,14 +294,6 @@ const canCreateBatch = () => {
|
||||
return false
|
||||
}
|
||||
|
||||
const getBatchCount = () => {
|
||||
call('frappe.client.get_count', {
|
||||
doctype: 'LMS Batch',
|
||||
}).then((data) => {
|
||||
batchCount.value = data
|
||||
})
|
||||
}
|
||||
|
||||
const breadcrumbs = computed(() => [
|
||||
{
|
||||
label: __('Batches'),
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
:text="__('Average Rating')"
|
||||
class="flex items-center"
|
||||
>
|
||||
<Star class="h-5 w-5 text-gray-100 fill-orange-500" />
|
||||
<Star class="size-4 text-transparent fill-yellow-500" />
|
||||
<span class="ml-1 text-ink-gray-7">
|
||||
{{ course.data.rating }}
|
||||
</span>
|
||||
|
||||
@@ -20,14 +20,12 @@
|
||||
</header>
|
||||
<div class="p-5 pb-10">
|
||||
<div
|
||||
v-if="courseCount"
|
||||
class="flex flex-col lg:flex-row space-y-4 lg:space-y-0 lg:items-center justify-between mb-5"
|
||||
>
|
||||
<div class="text-lg text-ink-gray-9 font-semibold">
|
||||
{{ __('All Courses') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="courses.data?.length || courseCount"
|
||||
class="flex flex-col space-y-2 lg:space-y-0 lg:flex-row lg:items-center lg:space-x-4"
|
||||
>
|
||||
<TabButtons :buttons="courseTabs" v-model="currentTab" />
|
||||
@@ -172,6 +170,8 @@ const identifyUserPersona = async () => {
|
||||
}
|
||||
|
||||
const getCourseCount = () => {
|
||||
if (!user.data) return
|
||||
|
||||
call('frappe.client.get_count', {
|
||||
doctype: 'LMS Course',
|
||||
}).then((data) => {
|
||||
|
||||
@@ -1,98 +1,96 @@
|
||||
import { useStorage } from "@vueuse/core";
|
||||
import { call } from "frappe-ui";
|
||||
import "../../../frappe/frappe/public/js/lib/posthog.js";
|
||||
|
||||
const APP = "lms";
|
||||
const SITENAME = window.location.hostname;
|
||||
import '../../../frappe/frappe/public/js/lib/posthog.js'
|
||||
import { createResource } from 'frappe-ui'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
posthog: any;
|
||||
posthog: any
|
||||
}
|
||||
}
|
||||
|
||||
const telemetry = useStorage("telemetry", {
|
||||
enabled: false,
|
||||
project_id: "",
|
||||
host: "",
|
||||
});
|
||||
|
||||
export async function init() {
|
||||
await set_enabled();
|
||||
if (!telemetry.value.enabled) return;
|
||||
try {
|
||||
await set_credentials();
|
||||
window.posthog.init(telemetry.value.project_id, {
|
||||
api_host: telemetry.value.host,
|
||||
autocapture: false,
|
||||
person_profiles: "always",
|
||||
capture_pageview: true,
|
||||
capture_pageleave: true,
|
||||
disable_session_recording: false,
|
||||
session_recording: {
|
||||
maskAllInputs: false,
|
||||
maskInputOptions: {
|
||||
password: true,
|
||||
},
|
||||
},
|
||||
loaded: (posthog) => {
|
||||
window.posthog = posthog;
|
||||
window.posthog.identify(SITENAME);
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.trace("Failed to initialize telemetry", e);
|
||||
telemetry.value.enabled = false;
|
||||
}
|
||||
type PosthogSettings = {
|
||||
posthog_project_id: string
|
||||
posthog_host: string
|
||||
enable_telemetry: boolean
|
||||
telemetry_site_age: number
|
||||
}
|
||||
|
||||
async function set_enabled() {
|
||||
if (telemetry.value.enabled) return;
|
||||
|
||||
await call("lms.lms.telemetry.is_enabled").then((res) => {
|
||||
telemetry.value.enabled = res;
|
||||
});
|
||||
}
|
||||
|
||||
async function set_credentials() {
|
||||
if (!telemetry.value.enabled) return;
|
||||
if (telemetry.value.project_id && telemetry.value.host) return;
|
||||
|
||||
await call("lms.lms.telemetry.get_credentials").then((res) => {
|
||||
telemetry.value.project_id = res.project_id;
|
||||
telemetry.value.host = res.telemetry_host;
|
||||
});
|
||||
}
|
||||
|
||||
interface CaptureOptions {
|
||||
data: {
|
||||
user: string;
|
||||
[key: string]: string | number | boolean | object;
|
||||
};
|
||||
user: string
|
||||
[key: string]: string | number | boolean | object
|
||||
}
|
||||
}
|
||||
|
||||
export function capture(
|
||||
let posthog: typeof window.posthog = window.posthog
|
||||
|
||||
// Posthog Settings
|
||||
let posthogSettings = createResource({
|
||||
url: 'lms.lms.telemetry.get_posthog_settings',
|
||||
cache: 'posthog_settings',
|
||||
onSuccess: (ps: PosthogSettings) => initPosthog(ps),
|
||||
})
|
||||
|
||||
let isTelemetryEnabled = () => {
|
||||
if (!posthogSettings.data) return false
|
||||
|
||||
return (
|
||||
posthogSettings.data.enable_telemetry &&
|
||||
posthogSettings.data.posthog_project_id &&
|
||||
posthogSettings.data.posthog_host
|
||||
)
|
||||
}
|
||||
|
||||
// Posthog Initialization
|
||||
function initPosthog(ps: PosthogSettings) {
|
||||
if (!isTelemetryEnabled()) return
|
||||
|
||||
posthog.init(ps.posthog_project_id, {
|
||||
api_host: ps.posthog_host,
|
||||
person_profiles: 'identified_only',
|
||||
autocapture: false,
|
||||
capture_pageview: true,
|
||||
capture_pageleave: true,
|
||||
enable_heatmaps: false,
|
||||
disable_session_recording: false,
|
||||
loaded: (ph: typeof posthog) => {
|
||||
window.posthog = ph
|
||||
ph.identify(window.location.hostname)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Posthog Functions
|
||||
function capture(
|
||||
event: string,
|
||||
options: CaptureOptions = { data: { user: "" } }
|
||||
options: CaptureOptions = { data: { user: '' } },
|
||||
) {
|
||||
if (!telemetry.value.enabled) return;
|
||||
window.posthog.capture(`${APP}_${event}`, options);
|
||||
if (!isTelemetryEnabled()) return
|
||||
window.posthog.capture(`lms_${event}`, options)
|
||||
}
|
||||
|
||||
export function recordSession() {
|
||||
if (!telemetry.value.enabled) return;
|
||||
if (window.posthog && window.posthog.__loaded) {
|
||||
window.posthog.startSessionRecording();
|
||||
function startRecording() {
|
||||
if (!isTelemetryEnabled()) return
|
||||
if (window.posthog?.__loaded) {
|
||||
window.posthog.startSessionRecording()
|
||||
}
|
||||
}
|
||||
|
||||
export function stopSession() {
|
||||
if (!telemetry.value.enabled) return;
|
||||
if (
|
||||
window.posthog &&
|
||||
window.posthog.__loaded &&
|
||||
window.posthog.sessionRecordingStarted()
|
||||
) {
|
||||
window.posthog.stopSessionRecording();
|
||||
}
|
||||
function stopRecording() {
|
||||
if (!isTelemetryEnabled()) return
|
||||
if (window.posthog?.__loaded && window.posthog.sessionRecordingStarted()) {
|
||||
window.posthog.stopSessionRecording()
|
||||
}
|
||||
}
|
||||
|
||||
// Posthog Plugin
|
||||
function posthogPlugin(app: any) {
|
||||
app.config.globalProperties.posthog = posthog
|
||||
if (!window.posthog?.length) posthogSettings.fetch()
|
||||
}
|
||||
|
||||
export {
|
||||
posthog,
|
||||
posthogSettings,
|
||||
posthogPlugin,
|
||||
capture,
|
||||
startRecording,
|
||||
stopRecording,
|
||||
}
|
||||
|
||||
@@ -561,3 +561,24 @@ export const openSettings = (category, close) => {
|
||||
settingsStore.activeTab = category
|
||||
settingsStore.isSettingsOpen = true
|
||||
}
|
||||
|
||||
export const cleanError = (message) => {
|
||||
// Remove HTML tags but keep the text within the tags
|
||||
|
||||
const cleanMessage = message.replace(/<[^>]+>/g, (match) => {
|
||||
return match.replace(/<\/?[^>]+(>|$)/g, '')
|
||||
})
|
||||
return cleanMessage
|
||||
.replace(/ /g, ' ')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, "'")
|
||||
.replace(/&/g, '&')
|
||||
.replace(/`/g, '`')
|
||||
.replace(/=/g, '=')
|
||||
.replace(///g, '/')
|
||||
.replace(/,/g, ',')
|
||||
.replace(/;/g, ';')
|
||||
.replace(/:/g, ':')
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "2.28.0"
|
||||
__version__ = "2.28.1"
|
||||
|
||||
@@ -356,6 +356,7 @@
|
||||
"fieldtype": "Section Break"
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [
|
||||
{
|
||||
@@ -371,8 +372,8 @@
|
||||
"link_fieldname": "batch_name"
|
||||
}
|
||||
],
|
||||
"modified": "2025-02-18 15:43:18.512504",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2025-05-21 13:30:28.904260",
|
||||
"modified_by": "sayali@frappe.io",
|
||||
"module": "LMS",
|
||||
"name": "LMS Batch",
|
||||
"owner": "Administrator",
|
||||
@@ -412,12 +413,22 @@
|
||||
"role": "Batch Evaluator",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "LMS Student",
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"show_title_field_in_link": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "title",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ class LMSBatch(Document):
|
||||
frappe.throw(_("Seat count cannot be negative."))
|
||||
|
||||
students = frappe.db.count("LMS Batch Enrollment", {"batch": self.name})
|
||||
if cint(self.seat_count) < students:
|
||||
if cint(self.seat_count) and cint(self.seat_count) < students:
|
||||
frappe.throw(_("There are no seats available in this batch."))
|
||||
|
||||
def validate_timetable(self):
|
||||
|
||||
@@ -73,10 +73,11 @@
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2025-01-13 19:02:58.259908",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2025-05-21 15:58:51.667270",
|
||||
"modified_by": "sayali@frappe.io",
|
||||
"module": "LMS",
|
||||
"name": "LMS Batch Feedback",
|
||||
"owner": "Administrator",
|
||||
@@ -106,7 +107,9 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
"states": [],
|
||||
"title_field": "member"
|
||||
}
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
import frappe
|
||||
from frappe.utils.telemetry import POSTHOG_HOST_FIELD, POSTHOG_PROJECT_FIELD
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def is_enabled():
|
||||
return bool(
|
||||
frappe.get_system_settings("enable_telemetry")
|
||||
and frappe.conf.get("posthog_host")
|
||||
and frappe.conf.get("posthog_project_id")
|
||||
)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_credentials():
|
||||
def get_posthog_settings():
|
||||
return {
|
||||
"project_id": frappe.conf.get("posthog_project_id"),
|
||||
"telemetry_host": frappe.conf.get("posthog_host"),
|
||||
"posthog_project_id": frappe.conf.get(POSTHOG_PROJECT_FIELD),
|
||||
"posthog_host": frappe.conf.get(POSTHOG_HOST_FIELD),
|
||||
"enable_telemetry": frappe.get_system_settings("enable_telemetry"),
|
||||
"telemetry_site_age": frappe.utils.telemetry.site_age(),
|
||||
}
|
||||
|
||||
706
lms/locale/ar.po
706
lms/locale/ar.po
File diff suppressed because it is too large
Load Diff
710
lms/locale/bs.po
710
lms/locale/bs.po
File diff suppressed because it is too large
Load Diff
706
lms/locale/de.po
706
lms/locale/de.po
File diff suppressed because it is too large
Load Diff
710
lms/locale/eo.po
710
lms/locale/eo.po
File diff suppressed because it is too large
Load Diff
708
lms/locale/es.po
708
lms/locale/es.po
File diff suppressed because it is too large
Load Diff
710
lms/locale/fa.po
710
lms/locale/fa.po
File diff suppressed because it is too large
Load Diff
708
lms/locale/fr.po
708
lms/locale/fr.po
File diff suppressed because it is too large
Load Diff
708
lms/locale/hr.po
708
lms/locale/hr.po
File diff suppressed because it is too large
Load Diff
706
lms/locale/hu.po
706
lms/locale/hu.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
706
lms/locale/pl.po
706
lms/locale/pl.po
File diff suppressed because it is too large
Load Diff
706
lms/locale/pt.po
706
lms/locale/pt.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
708
lms/locale/ru.po
708
lms/locale/ru.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
712
lms/locale/sv.po
712
lms/locale/sv.po
File diff suppressed because it is too large
Load Diff
706
lms/locale/th.po
706
lms/locale/th.po
File diff suppressed because it is too large
Load Diff
708
lms/locale/tr.po
708
lms/locale/tr.po
File diff suppressed because it is too large
Load Diff
756
lms/locale/zh.po
756
lms/locale/zh.po
File diff suppressed because it is too large
Load Diff
@@ -2,11 +2,11 @@
|
||||
"name": "frappe_lms",
|
||||
"version": "1.0.0",
|
||||
"description": "Easy to use, open-source, Learning Management System",
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
"frappe-ui",
|
||||
"frontend"
|
||||
],
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test-local": "cypress open --e2e --browser chrome",
|
||||
"postinstall": "cd frontend && yarn install --check-files",
|
||||
@@ -26,7 +26,8 @@
|
||||
"homepage": "https://github.com/frappe/lms#readme",
|
||||
"devDependencies": {
|
||||
"cypress": "^13.9.0",
|
||||
"cypress-file-upload": "^5.0.8"
|
||||
"cypress-file-upload": "^5.0.8",
|
||||
"cypress-real-events": "^1.14.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"pre-commit": "^1.2.2"
|
||||
|
||||
561
yarn.lock
561
yarn.lock
@@ -35,7 +35,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8"
|
||||
integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==
|
||||
|
||||
"@babel/parser@^7.25.3":
|
||||
"@babel/parser@^7.27.2":
|
||||
version "7.27.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.2.tgz#577518bedb17a2ce4212afd052e01f7df0941127"
|
||||
integrity sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==
|
||||
@@ -262,9 +262,9 @@
|
||||
"@codexteam/icons" "^0.0.6"
|
||||
|
||||
"@editorjs/table@^2.4.2":
|
||||
version "2.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@editorjs/table/-/table-2.4.4.tgz#724cbebd2c99b929bd41d31a147fdaf690ae2c81"
|
||||
integrity sha512-2wWjxk48C9Z7uaBZIS5dML81c2VsD47Va9J4RDd2UboxcnYV8OZ4oYxKafH5RJIGPj8ykGaROIzyDVR1N4e7Cg==
|
||||
version "2.4.5"
|
||||
resolved "https://registry.yarnpkg.com/@editorjs/table/-/table-2.4.5.tgz#bb2ce9962935088e3d24a20e799acb9526b90e7b"
|
||||
integrity sha512-pF48R2wc5m0c+N+RjtCLXBGZd23Rl7EjfSFpmcSViwNsu5RwMgYGrEiQ8mzVh98mbvYQwXm/NYBi9DEUUs970A==
|
||||
dependencies:
|
||||
"@codexteam/icons" "^0.0.6"
|
||||
|
||||
@@ -496,20 +496,20 @@
|
||||
mlly "^1.7.4"
|
||||
|
||||
"@inquirer/confirm@^5.0.0":
|
||||
version "5.1.10"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-5.1.10.tgz#de3732cb7ae9333bd3e354afee6a6ef8cf28d951"
|
||||
integrity sha512-FxbQ9giWxUWKUk2O5XZ6PduVnH2CZ/fmMKMBkH71MHJvWr7WL5AHKevhzF1L5uYWB2P548o1RzVxrNd3dpmk6g==
|
||||
version "5.1.12"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-5.1.12.tgz#387037889a5a558ceefe52e978228630aa6e7d0e"
|
||||
integrity sha512-dpq+ielV9/bqgXRUbNH//KsY6WEw9DrGPmipkpmgC1Y46cwuBTNx7PXFWTjc3MQ+urcc0QxoVHcMI0FW4Ok0hg==
|
||||
dependencies:
|
||||
"@inquirer/core" "^10.1.11"
|
||||
"@inquirer/type" "^3.0.6"
|
||||
"@inquirer/core" "^10.1.13"
|
||||
"@inquirer/type" "^3.0.7"
|
||||
|
||||
"@inquirer/core@^10.1.11":
|
||||
version "10.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-10.1.11.tgz#4022032b5b6b35970e1c3fcfc522bc250ef8810d"
|
||||
integrity sha512-BXwI/MCqdtAhzNQlBEFE7CEflhPkl/BqvAuV/aK6lW3DClIfYVDWPP/kXuXHtBWC7/EEbNqd/1BGq2BGBBnuxw==
|
||||
"@inquirer/core@^10.1.13":
|
||||
version "10.1.13"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-10.1.13.tgz#8f1ecfaba288fd2d705c7ac0690371464cf687b0"
|
||||
integrity sha512-1viSxebkYN2nJULlzCxES6G9/stgHSepZ9LqqfdIGPHj5OHhiBUXVS0a6R0bEC2A+VL4D9w6QB66ebCr6HGllA==
|
||||
dependencies:
|
||||
"@inquirer/figures" "^1.0.11"
|
||||
"@inquirer/type" "^3.0.6"
|
||||
"@inquirer/figures" "^1.0.12"
|
||||
"@inquirer/type" "^3.0.7"
|
||||
ansi-escapes "^4.3.2"
|
||||
cli-width "^4.1.0"
|
||||
mute-stream "^2.0.0"
|
||||
@@ -517,27 +517,27 @@
|
||||
wrap-ansi "^6.2.0"
|
||||
yoctocolors-cjs "^2.1.2"
|
||||
|
||||
"@inquirer/figures@^1.0.11":
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.11.tgz#4744e6db95288fea1dead779554859710a959a21"
|
||||
integrity sha512-eOg92lvrn/aRUqbxRyvpEWnrvRuTYRifixHkYVpJiygTgVSBIHDqLh0SrMQXkafvULg3ck11V7xvR+zcgvpHFw==
|
||||
"@inquirer/figures@^1.0.12":
|
||||
version "1.0.12"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.12.tgz#667d6254cc7ba3b0c010a323d78024a1d30c6053"
|
||||
integrity sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==
|
||||
|
||||
"@inquirer/type@^3.0.6":
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-3.0.6.tgz#2500e435fc2014c5250eec3279f42b70b64089bd"
|
||||
integrity sha512-/mKVCtVpyBu3IDarv0G+59KC4stsD5mDsGpYh+GKs1NZT88Jh52+cuoA1AtLk2Q0r/quNl+1cSUyLRHBFeD0XA==
|
||||
"@inquirer/type@^3.0.7":
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-3.0.7.tgz#b46bcf377b3172dbc768fdbd053e6492ad801a09"
|
||||
integrity sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==
|
||||
|
||||
"@internationalized/date@^3.5.0", "@internationalized/date@^3.5.4":
|
||||
version "3.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.8.0.tgz#24fb301029224351381aa87cba853ca1093af094"
|
||||
integrity sha512-J51AJ0fEL68hE4CwGPa6E0PO6JDaVLd8aln48xFCSy7CZkZc96dGEGmLs2OEEbBxcsVZtfrqkXJwI2/MSG8yKw==
|
||||
version "3.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.8.1.tgz#fb3709440060a9efa0722615e83550e682e83221"
|
||||
integrity sha512-PgVE6B6eIZtzf9Gu5HvJxRK3ufUFz9DhspELuhW/N0GuMGMTLvPQNRkHP2hTuP9lblOk+f+1xi96sPiPXANXAA==
|
||||
dependencies:
|
||||
"@swc/helpers" "^0.5.0"
|
||||
|
||||
"@internationalized/number@^3.5.0", "@internationalized/number@^3.5.3":
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.6.1.tgz#7c13cc55eb546aa3d42b8d5e7ac7db69a082fec7"
|
||||
integrity sha512-UVsb4bCwbL944E0SX50CHFtWEeZ2uB5VozZ5yDXJdq6iPZsZO5p+bjVMZh2GxHf4Bs/7xtDCcPwEa2NU9DaG/g==
|
||||
version "3.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.6.2.tgz#504bf772238420c06b63ec58957c1cfcf6d92755"
|
||||
integrity sha512-E5QTOlMg9wo5OrKdHD6edo1JJlIoOsylh0+mbf0evi1tHJwMZfJSaBpGtnJV9N7w3jeiioox9EG/EWRWPh82vg==
|
||||
dependencies:
|
||||
"@swc/helpers" "^0.5.0"
|
||||
|
||||
@@ -694,105 +694,105 @@
|
||||
resolved "https://registry.yarnpkg.com/@remirror/core-constants/-/core-constants-3.0.0.tgz#96fdb89d25c62e7b6a5d08caf0ce5114370e3b8f"
|
||||
integrity sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.2.tgz#c228d00a41f0dbd6fb8b7ea819bbfbf1c1157a10"
|
||||
integrity sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==
|
||||
"@rollup/rollup-android-arm-eabi@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz#f39f09f60d4a562de727c960d7b202a2cf797424"
|
||||
integrity sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==
|
||||
|
||||
"@rollup/rollup-android-arm64@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.2.tgz#e2b38d0c912169fd55d7e38d723aada208d37256"
|
||||
integrity sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==
|
||||
"@rollup/rollup-android-arm64@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz#d19af7e23760717f1d879d4ca3d2cd247742dff2"
|
||||
integrity sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==
|
||||
|
||||
"@rollup/rollup-darwin-arm64@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.2.tgz#1fddb3690f2ae33df16d334c613377f05abe4878"
|
||||
integrity sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==
|
||||
"@rollup/rollup-darwin-arm64@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz#1c3a2fbf205d80641728e05f4a56c909e95218b7"
|
||||
integrity sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==
|
||||
|
||||
"@rollup/rollup-darwin-x64@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.2.tgz#818298d11c8109e1112590165142f14be24b396d"
|
||||
integrity sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==
|
||||
"@rollup/rollup-darwin-x64@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz#aa66d2ba1a25e609500e13bef06dc0e71cc0c0d4"
|
||||
integrity sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==
|
||||
|
||||
"@rollup/rollup-freebsd-arm64@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.2.tgz#91a28dc527d5bed7f9ecf0e054297b3012e19618"
|
||||
integrity sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==
|
||||
"@rollup/rollup-freebsd-arm64@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz#df10a7b6316a0ef1028c6ca71a081124c537e30d"
|
||||
integrity sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==
|
||||
|
||||
"@rollup/rollup-freebsd-x64@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.2.tgz#28acadefa76b5c7bede1576e065b51d335c62c62"
|
||||
integrity sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==
|
||||
"@rollup/rollup-freebsd-x64@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz#a3fdce8a05e95b068cbcb46e4df5185e407d0c35"
|
||||
integrity sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.2.tgz#819691464179cbcd9a9f9d3dc7617954840c6186"
|
||||
integrity sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==
|
||||
"@rollup/rollup-linux-arm-gnueabihf@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz#49f766c55383bd0498014a9d76924348c2f3890c"
|
||||
integrity sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.2.tgz#d149207039e4189e267e8724050388effc80d704"
|
||||
integrity sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==
|
||||
"@rollup/rollup-linux-arm-musleabihf@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz#1d4d7d32fc557e17d52e1857817381ea365e2959"
|
||||
integrity sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.2.tgz#fa72ebddb729c3c6d88973242f1a2153c83e86ec"
|
||||
integrity sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==
|
||||
"@rollup/rollup-linux-arm64-gnu@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz#f4fc317268441e9589edad3be8f62b6c03009bc1"
|
||||
integrity sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.2.tgz#2054216e34469ab8765588ebf343d531fc3c9228"
|
||||
integrity sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==
|
||||
"@rollup/rollup-linux-arm64-musl@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz#63a1f1b0671cb17822dabae827fef0e443aebeb7"
|
||||
integrity sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.2.tgz#818de242291841afbfc483a84f11e9c7a11959bc"
|
||||
integrity sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==
|
||||
"@rollup/rollup-linux-loongarch64-gnu@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz#c659b01cc6c0730b547571fc3973e1e955369f98"
|
||||
integrity sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.2.tgz#0bb4cb8fc4a2c635f68c1208c924b2145eb647cb"
|
||||
integrity sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==
|
||||
"@rollup/rollup-linux-powerpc64le-gnu@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz#612e746f9ad7e58480f964d65e0d6c3f4aae69a8"
|
||||
integrity sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.2.tgz#4b3b8e541b7b13e447ae07774217d98c06f6926d"
|
||||
integrity sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==
|
||||
"@rollup/rollup-linux-riscv64-gnu@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz#4610dbd1dcfbbae32fbc10c20ae7387acb31110c"
|
||||
integrity sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.2.tgz#e065405e67d8bd64a7d0126c931bd9f03910817f"
|
||||
integrity sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==
|
||||
"@rollup/rollup-linux-riscv64-musl@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz#054911fab40dc83fafc21e470193c058108f19d8"
|
||||
integrity sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.2.tgz#dda3265bbbfe16a5d0089168fd07f5ebb2a866fe"
|
||||
integrity sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==
|
||||
"@rollup/rollup-linux-s390x-gnu@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz#98896eca8012547c7f04bd07eaa6896825f9e1a5"
|
||||
integrity sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.2.tgz#90993269b8b995b4067b7b9d72ff1c360ef90a17"
|
||||
integrity sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==
|
||||
"@rollup/rollup-linux-x64-gnu@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz#01cf56844a1e636ee80dfb364e72c2b7142ad896"
|
||||
integrity sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==
|
||||
|
||||
"@rollup/rollup-linux-x64-musl@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.2.tgz#fdf5b09fd121eb8d977ebb0fda142c7c0167b8de"
|
||||
integrity sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==
|
||||
"@rollup/rollup-linux-x64-musl@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz#e67c7531df6dff0b4c241101d4096617fbca87c3"
|
||||
integrity sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.2.tgz#6397e1e012db64dfecfed0774cb9fcf89503d716"
|
||||
integrity sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==
|
||||
"@rollup/rollup-win32-arm64-msvc@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz#7eeada98444e580674de6989284e4baacd48ea65"
|
||||
integrity sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.2.tgz#df0991464a52a35506103fe18d29913bf8798a0c"
|
||||
integrity sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==
|
||||
"@rollup/rollup-win32-ia32-msvc@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz#516c4b54f80587b4a390aaf4940b40870271d35d"
|
||||
integrity sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc@4.40.2":
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.2.tgz#8dae04d01a2cbd84d6297d99356674c6b993f0fc"
|
||||
integrity sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==
|
||||
"@rollup/rollup-win32-x64-msvc@4.41.1":
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz#848f99b0d9936d92221bb6070baeff4db6947a30"
|
||||
integrity sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==
|
||||
|
||||
"@socket.io/component-emitter@~3.1.0":
|
||||
version "3.1.2"
|
||||
@@ -850,17 +850,17 @@
|
||||
lodash.merge "^4.6.2"
|
||||
postcss-selector-parser "6.0.10"
|
||||
|
||||
"@tanstack/virtual-core@3.13.8":
|
||||
version "3.13.8"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.13.8.tgz#6346e688521c1f086f508ccbebaad0b472a2aefb"
|
||||
integrity sha512-BT6w89Hqy7YKaWewYzmecXQzcJh6HTBbKYJIIkMaNU49DZ06LoTV3z32DWWEdUsgW6n1xTmwTLs4GtWrZC261w==
|
||||
"@tanstack/virtual-core@3.13.9":
|
||||
version "3.13.9"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.13.9.tgz#62b4d2d4351d658101664beacf088fbd061190bf"
|
||||
integrity sha512-3jztt0jpaoJO5TARe2WIHC1UQC3VMLAFUW5mmMo0yrkwtDB2AQP0+sh10BVUpWrnvHjSLvzFizydtEGLCJKFoQ==
|
||||
|
||||
"@tanstack/vue-virtual@^3.0.0-beta.60", "@tanstack/vue-virtual@^3.12.0", "@tanstack/vue-virtual@^3.8.1":
|
||||
version "3.13.8"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/vue-virtual/-/vue-virtual-3.13.8.tgz#5df214b258e6f62ce775a2bfa8d8919043a2bb60"
|
||||
integrity sha512-CqyjKVc88YlE8JPth8a5Gi4CUoYrwJ2PZxtFbhoekx8Z2qqymxX2jzkbUMKFsX4EVNET90D5bLsG3epyozbzcg==
|
||||
version "3.13.9"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/vue-virtual/-/vue-virtual-3.13.9.tgz#4f5eaab36a511a93123f27c41aca8d0bac51d1ac"
|
||||
integrity sha512-HsvHaOo+o52cVcPhomKDZ3CMpTF/B2qg+BhPHIQJwzn4VIqDyt/rRVqtIomG6jE83IFsE2vlr6cmx7h3dHA0SA==
|
||||
dependencies:
|
||||
"@tanstack/virtual-core" "3.13.8"
|
||||
"@tanstack/virtual-core" "3.13.9"
|
||||
|
||||
"@tiptap/core@^2.11.7", "@tiptap/core@^2.12.0":
|
||||
version "2.12.0"
|
||||
@@ -1170,9 +1170,9 @@
|
||||
integrity sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==
|
||||
|
||||
"@types/node@*":
|
||||
version "22.15.17"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.17.tgz#355ccec95f705b664e4332bb64a7f07db30b7055"
|
||||
integrity sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==
|
||||
version "22.15.21"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.21.tgz#196ef14fe20d87f7caf1e7b39832767f9a995b77"
|
||||
integrity sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==
|
||||
dependencies:
|
||||
undici-types "~6.21.0"
|
||||
|
||||
@@ -1287,90 +1287,90 @@
|
||||
loupe "^3.1.2"
|
||||
tinyrainbow "^1.2.0"
|
||||
|
||||
"@vue/compiler-core@3.5.13":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.13.tgz#b0ae6c4347f60c03e849a05d34e5bf747c9bda05"
|
||||
integrity sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==
|
||||
"@vue/compiler-core@3.5.14":
|
||||
version "3.5.14"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.14.tgz#3676685c04c48a5b4a5515b3b2842e98342c555c"
|
||||
integrity sha512-k7qMHMbKvoCXIxPhquKQVw3Twid3Kg4s7+oYURxLGRd56LiuHJVrvFKI4fm2AM3c8apqODPfVJGoh8nePbXMRA==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.25.3"
|
||||
"@vue/shared" "3.5.13"
|
||||
"@babel/parser" "^7.27.2"
|
||||
"@vue/shared" "3.5.14"
|
||||
entities "^4.5.0"
|
||||
estree-walker "^2.0.2"
|
||||
source-map-js "^1.2.0"
|
||||
source-map-js "^1.2.1"
|
||||
|
||||
"@vue/compiler-dom@3.5.13":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz#bb1b8758dbc542b3658dda973b98a1c9311a8a58"
|
||||
integrity sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==
|
||||
"@vue/compiler-dom@3.5.14":
|
||||
version "3.5.14"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.14.tgz#bbf27421f80f7b8873000edceecd817c4abf438a"
|
||||
integrity sha512-1aOCSqxGOea5I80U2hQJvXYpPm/aXo95xL/m/mMhgyPUsKe9jhjwWpziNAw7tYRnbz1I61rd9Mld4W9KmmRoug==
|
||||
dependencies:
|
||||
"@vue/compiler-core" "3.5.13"
|
||||
"@vue/shared" "3.5.13"
|
||||
"@vue/compiler-core" "3.5.14"
|
||||
"@vue/shared" "3.5.14"
|
||||
|
||||
"@vue/compiler-sfc@3.5.13":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz#461f8bd343b5c06fac4189c4fef8af32dea82b46"
|
||||
integrity sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==
|
||||
"@vue/compiler-sfc@3.5.14":
|
||||
version "3.5.14"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.14.tgz#fc3db30a1c744139d41bb57bb451d783415fce4b"
|
||||
integrity sha512-9T6m/9mMr81Lj58JpzsiSIjBgv2LiVoWjIVa7kuXHICUi8LiDSIotMpPRXYJsXKqyARrzjT24NAwttrMnMaCXA==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.25.3"
|
||||
"@vue/compiler-core" "3.5.13"
|
||||
"@vue/compiler-dom" "3.5.13"
|
||||
"@vue/compiler-ssr" "3.5.13"
|
||||
"@vue/shared" "3.5.13"
|
||||
"@babel/parser" "^7.27.2"
|
||||
"@vue/compiler-core" "3.5.14"
|
||||
"@vue/compiler-dom" "3.5.14"
|
||||
"@vue/compiler-ssr" "3.5.14"
|
||||
"@vue/shared" "3.5.14"
|
||||
estree-walker "^2.0.2"
|
||||
magic-string "^0.30.11"
|
||||
postcss "^8.4.48"
|
||||
source-map-js "^1.2.0"
|
||||
magic-string "^0.30.17"
|
||||
postcss "^8.5.3"
|
||||
source-map-js "^1.2.1"
|
||||
|
||||
"@vue/compiler-ssr@3.5.13":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz#e771adcca6d3d000f91a4277c972a996d07f43ba"
|
||||
integrity sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==
|
||||
"@vue/compiler-ssr@3.5.14":
|
||||
version "3.5.14"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.14.tgz#013174ee6bbf3ee291a6df247a3feb6eb43d808b"
|
||||
integrity sha512-Y0G7PcBxr1yllnHuS/NxNCSPWnRGH4Ogrp0tsLA5QemDZuJLs99YjAKQ7KqkHE0vCg4QTKlQzXLKCMF7WPSl7Q==
|
||||
dependencies:
|
||||
"@vue/compiler-dom" "3.5.13"
|
||||
"@vue/shared" "3.5.13"
|
||||
"@vue/compiler-dom" "3.5.14"
|
||||
"@vue/shared" "3.5.14"
|
||||
|
||||
"@vue/devtools-api@^6.6.3", "@vue/devtools-api@^6.6.4":
|
||||
version "6.6.4"
|
||||
resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz#cbe97fe0162b365edc1dba80e173f90492535343"
|
||||
integrity sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==
|
||||
|
||||
"@vue/reactivity@3.5.13":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.13.tgz#b41ff2bb865e093899a22219f5b25f97b6fe155f"
|
||||
integrity sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==
|
||||
"@vue/reactivity@3.5.14":
|
||||
version "3.5.14"
|
||||
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.14.tgz#814fb4ba84a9560d2752b9982fdd2b76e4a5e5a3"
|
||||
integrity sha512-7cK1Hp343Fu/SUCCO52vCabjvsYu7ZkOqyYu7bXV9P2yyfjUMUXHZafEbq244sP7gf+EZEz+77QixBTuEqkQQw==
|
||||
dependencies:
|
||||
"@vue/shared" "3.5.13"
|
||||
"@vue/shared" "3.5.14"
|
||||
|
||||
"@vue/runtime-core@3.5.13":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.13.tgz#1fafa4bf0b97af0ebdd9dbfe98cd630da363a455"
|
||||
integrity sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==
|
||||
"@vue/runtime-core@3.5.14":
|
||||
version "3.5.14"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.14.tgz#f4084cad032be3452d8f137035fcd93c182f7149"
|
||||
integrity sha512-w9JWEANwHXNgieAhxPpEpJa+0V5G0hz3NmjAZwlOebtfKyp2hKxKF0+qSh0Xs6/PhfGihuSdqMprMVcQU/E6ag==
|
||||
dependencies:
|
||||
"@vue/reactivity" "3.5.13"
|
||||
"@vue/shared" "3.5.13"
|
||||
"@vue/reactivity" "3.5.14"
|
||||
"@vue/shared" "3.5.14"
|
||||
|
||||
"@vue/runtime-dom@3.5.13":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz#610fc795de9246300e8ae8865930d534e1246215"
|
||||
integrity sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==
|
||||
"@vue/runtime-dom@3.5.14":
|
||||
version "3.5.14"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.14.tgz#59ea4a5fe3ed93fb8f725c1c722a0fe8d8ae16cf"
|
||||
integrity sha512-lCfR++IakeI35TVR80QgOelsUIdcKjd65rWAMfdSlCYnaEY5t3hYwru7vvcWaqmrK+LpI7ZDDYiGU5V3xjMacw==
|
||||
dependencies:
|
||||
"@vue/reactivity" "3.5.13"
|
||||
"@vue/runtime-core" "3.5.13"
|
||||
"@vue/shared" "3.5.13"
|
||||
"@vue/reactivity" "3.5.14"
|
||||
"@vue/runtime-core" "3.5.14"
|
||||
"@vue/shared" "3.5.14"
|
||||
csstype "^3.1.3"
|
||||
|
||||
"@vue/server-renderer@3.5.13":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.13.tgz#429ead62ee51de789646c22efe908e489aad46f7"
|
||||
integrity sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==
|
||||
"@vue/server-renderer@3.5.14":
|
||||
version "3.5.14"
|
||||
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.14.tgz#adcaf30ddcf0064a28ce832d29f430bd0db3ef18"
|
||||
integrity sha512-Rf/ISLqokIvcySIYnv3tNWq40PLpNLDLSJwwVWzG6MNtyIhfbcrAxo5ZL9nARJhqjZyWWa40oRb2IDuejeuv6w==
|
||||
dependencies:
|
||||
"@vue/compiler-ssr" "3.5.13"
|
||||
"@vue/shared" "3.5.13"
|
||||
"@vue/compiler-ssr" "3.5.14"
|
||||
"@vue/shared" "3.5.14"
|
||||
|
||||
"@vue/shared@3.5.13":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.13.tgz#87b309a6379c22b926e696893237826f64339b6f"
|
||||
integrity sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==
|
||||
"@vue/shared@3.5.14":
|
||||
version "3.5.14"
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.14.tgz#8fcdc6c69661a1163c173cafb6129c3f8ad01122"
|
||||
integrity sha512-oXTwNxVfc9EtP1zzXAlSlgARLXNC84frFYkS0HHz0h3E4WZSP9sywqjqzGCP9Y34M8ipNmd380pVgmMuwELDyQ==
|
||||
|
||||
"@vueuse/core@^10.11.0", "@vueuse/core@^10.4.1":
|
||||
version "10.11.1"
|
||||
@@ -1563,9 +1563,9 @@ argparse@^2.0.1:
|
||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
||||
|
||||
aria-hidden@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.4.tgz#b78e383fdbc04d05762c78b4a25a501e736c4522"
|
||||
integrity sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.6.tgz#73051c9b088114c795b1ea414e9c0fff874ffc1a"
|
||||
integrity sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
@@ -2107,6 +2107,11 @@ cypress-file-upload@^5.0.8:
|
||||
resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz#d8824cbeaab798e44be8009769f9a6c9daa1b4a1"
|
||||
integrity sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g==
|
||||
|
||||
cypress-real-events@^1.14.0:
|
||||
version "1.14.0"
|
||||
resolved "https://registry.yarnpkg.com/cypress-real-events/-/cypress-real-events-1.14.0.tgz#c5495db50a2bd247f4accde983af7153566945d3"
|
||||
integrity sha512-XmI8y3OZLh6cjRroPalzzS++iv+pGCaD9G9kfIbtspgv7GVsDt30dkZvSXfgZb4rAN+3pOkMVB7e0j4oXydW7Q==
|
||||
|
||||
cypress@^13.9.0:
|
||||
version "13.17.0"
|
||||
resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.17.0.tgz#34c3d68080c4497eace0f353bd1629587a5f600d"
|
||||
@@ -2184,10 +2189,10 @@ debug@2.6.9:
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@4, debug@^4.1.1, debug@^4.3.4, debug@^4.3.7, debug@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
|
||||
integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
|
||||
debug@4, debug@^4.1.1, debug@^4.3.4, debug@^4.3.7, debug@^4.4.0, debug@^4.4.1:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
|
||||
integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
|
||||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
@@ -2322,9 +2327,9 @@ ee-first@1.1.1:
|
||||
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
|
||||
|
||||
electron-to-chromium@^1.5.149:
|
||||
version "1.5.152"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.152.tgz#bcdd39567e291b930ec26b930031137a05593695"
|
||||
integrity sha512-xBOfg/EBaIlVsHipHl2VdTPJRSvErNUaqW8ejTq5OlOlIYx1wOllCHsAvAIrr55jD1IYEfdR86miUEt8H5IeJg==
|
||||
version "1.5.157"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.157.tgz#553b122522ac7bba6f1a0dd7d50b14f297736f75"
|
||||
integrity sha512-/0ybgsQd1muo8QlnuTpKwtl0oX5YMlUGbm8xyqgDU00motRkKFFbUJySAQBWcY79rVqNLWIWa87BGVGClwAB2w==
|
||||
|
||||
emoji-regex@^10.3.0:
|
||||
version "10.4.0"
|
||||
@@ -2662,9 +2667,9 @@ finalhandler@1.1.2:
|
||||
unpipe "~1.0.0"
|
||||
|
||||
flexsearch@*:
|
||||
version "0.8.164"
|
||||
resolved "https://registry.yarnpkg.com/flexsearch/-/flexsearch-0.8.164.tgz#2d1277249d6dec8eb745358fa64543ddbddc9e05"
|
||||
integrity sha512-tauQG+NlwSWW6uL3BIJdHNEXYiei2xTR3H/mrjNadAOwvXgiLbLvLzQWSJvD31Yn0+1lAxG2NVRndywGnDZZiA==
|
||||
version "0.8.204"
|
||||
resolved "https://registry.yarnpkg.com/flexsearch/-/flexsearch-0.8.204.tgz#843f295e8f2aa3b3326d4bbee3ebe761a4a73cec"
|
||||
integrity sha512-Vh+WUZfUHsVP6w4o5uAkYle8Gz/oEuztSWvpSY3h71AE8ox+goTQ2X5YG4x6VlKKfubkMwhewk8kBTOVKMObHA==
|
||||
|
||||
flexsearch@0.7.21:
|
||||
version "0.7.21"
|
||||
@@ -2699,6 +2704,58 @@ 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.147:
|
||||
version "0.1.147"
|
||||
resolved "https://registry.yarnpkg.com/frappe-ui/-/frappe-ui-0.1.147.tgz#c4fe061b52d8e45a24de34a7d36257d2277aa965"
|
||||
integrity sha512-4yoT2Qw8M8NbDjgnYt83YuyMIGVVCdN+gIRCSZD9NpLQZpyyf0QJOsSrEIwkRdtV644L+4XknA0pv3UgFOkHtQ==
|
||||
dependencies:
|
||||
"@floating-ui/vue" "^1.1.6"
|
||||
"@headlessui/vue" "^1.7.14"
|
||||
"@popperjs/core" "^2.11.2"
|
||||
"@tailwindcss/forms" "^0.5.3"
|
||||
"@tailwindcss/typography" "^0.5.16"
|
||||
"@tiptap/core" "^2.11.7"
|
||||
"@tiptap/extension-code-block" "^2.11.9"
|
||||
"@tiptap/extension-code-block-lowlight" "^2.11.5"
|
||||
"@tiptap/extension-color" "^2.0.3"
|
||||
"@tiptap/extension-heading" "^2.12.0"
|
||||
"@tiptap/extension-highlight" "^2.0.3"
|
||||
"@tiptap/extension-image" "^2.0.3"
|
||||
"@tiptap/extension-link" "^2.0.3"
|
||||
"@tiptap/extension-mention" "^2.0.3"
|
||||
"@tiptap/extension-placeholder" "^2.0.3"
|
||||
"@tiptap/extension-table" "^2.0.3"
|
||||
"@tiptap/extension-table-cell" "^2.0.3"
|
||||
"@tiptap/extension-table-header" "^2.0.3"
|
||||
"@tiptap/extension-table-row" "^2.0.3"
|
||||
"@tiptap/extension-text-align" "^2.0.3"
|
||||
"@tiptap/extension-text-style" "^2.0.3"
|
||||
"@tiptap/extension-typography" "^2.0.3"
|
||||
"@tiptap/pm" "^2.0.3"
|
||||
"@tiptap/starter-kit" "^2.0.3"
|
||||
"@tiptap/suggestion" "^2.0.3"
|
||||
"@tiptap/vue-3" "^2.0.3"
|
||||
"@vueuse/core" "^10.4.1"
|
||||
dayjs "^1.11.13"
|
||||
echarts "^5.6.0"
|
||||
feather-icons "^4.28.0"
|
||||
idb-keyval "^6.2.0"
|
||||
lowlight "^3.3.0"
|
||||
lucide-static "^0.479.0"
|
||||
ora "5.4.1"
|
||||
prettier "^3.3.2"
|
||||
prosemirror-model "^1.25.1"
|
||||
prosemirror-state "^1.4.3"
|
||||
prosemirror-view "^1.39.2"
|
||||
radix-vue "^1.5.3"
|
||||
reka-ui "^2.0.2"
|
||||
showdown "^2.1.0"
|
||||
socket.io-client "^4.5.1"
|
||||
tippy.js "^6.3.7"
|
||||
typescript "^5.0.2"
|
||||
unplugin-icons "^22.1.0"
|
||||
unplugin-vue-components "^28.4.1"
|
||||
|
||||
fs-extra@^10.1.0:
|
||||
version "10.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
|
||||
@@ -3421,7 +3478,7 @@ lucide-vue-next@^0.383.0:
|
||||
resolved "https://registry.yarnpkg.com/lucide-vue-next/-/lucide-vue-next-0.383.0.tgz#7222eea85c185634ceb6d494d5153a6868805a07"
|
||||
integrity sha512-paQmd2cHAye7Zl/lA0avZN2efZxFkMehfoori1BiHKX//KQG4DVuy00yl4YHVQ6h1B4EsR+QDRCpVUtwvKUBRw==
|
||||
|
||||
magic-string@^0.30.11, magic-string@^0.30.12, magic-string@^0.30.17:
|
||||
magic-string@^0.30.12, magic-string@^0.30.17:
|
||||
version "0.30.17"
|
||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453"
|
||||
integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==
|
||||
@@ -3579,9 +3636,9 @@ ms@^2.1.1, ms@^2.1.3:
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
msw@^2.7.0:
|
||||
version "2.8.2"
|
||||
resolved "https://registry.yarnpkg.com/msw/-/msw-2.8.2.tgz#a35545275403da472f4ed2152cd3c77000db544c"
|
||||
integrity sha512-ugu8RBgUj6//RD0utqDDPdS+QIs36BKYkDAM6u59hcMVtFM4PM0vW4l3G1R+1uCWP2EWFUG8reT/gPXVEtx7/w==
|
||||
version "2.8.4"
|
||||
resolved "https://registry.yarnpkg.com/msw/-/msw-2.8.4.tgz#e61f50f5bc891e5b81655e4450650b587b761dd5"
|
||||
integrity sha512-GLU8gx0o7RBG/3x/eTnnLd5S5ZInxXRRRMN8GJwaPZ4jpJTxzQfWGvwr90e8L5dkKJnz+gT4gQYCprLy/c4kVw==
|
||||
dependencies:
|
||||
"@bundled-es-modules/cookie" "^2.0.1"
|
||||
"@bundled-es-modules/statuses" "^1.0.1"
|
||||
@@ -3617,9 +3674,9 @@ mz@^2.7.0:
|
||||
thenify-all "^1.0.0"
|
||||
|
||||
nano-spawn@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/nano-spawn/-/nano-spawn-1.0.1.tgz#c8e4c1e133e567e3efba44041dcfb12113d861b6"
|
||||
integrity sha512-BfcvzBlUTxSDWfT+oH7vd6CbUV+rThLLHCIym/QO6GGLBsyVXleZs00fto2i2jzC/wPiBYk5jyOmpXWg4YopiA==
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/nano-spawn/-/nano-spawn-1.0.2.tgz#9853795681f0e96ef6f39104c2e4347b6ba79bf6"
|
||||
integrity sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg==
|
||||
|
||||
nanoid@^3.3.8:
|
||||
version "3.3.11"
|
||||
@@ -3974,7 +4031,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0:
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
|
||||
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
||||
|
||||
postcss@^8.4.21, postcss@^8.4.43, postcss@^8.4.47, postcss@^8.4.48, postcss@^8.4.5:
|
||||
postcss@^8.4.21, postcss@^8.4.43, postcss@^8.4.47, postcss@^8.4.5, postcss@^8.5.3:
|
||||
version "8.5.3"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb"
|
||||
integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==
|
||||
@@ -4163,9 +4220,9 @@ prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transfor
|
||||
prosemirror-model "^1.21.0"
|
||||
|
||||
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.37.0, prosemirror-view@^1.39.1, prosemirror-view@^1.39.2:
|
||||
version "1.39.2"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.39.2.tgz#178743c9694fec5ed498d48e46d4a31bc1ef0936"
|
||||
integrity sha512-BmOkml0QWNob165gyUxXi5K5CVUgVPpqMEAAml/qzgKn9boLUWVPzQ6LtzXw8Cn1GtRQX4ELumPxqtLTDaAKtg==
|
||||
version "1.39.3"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.39.3.tgz#54fa4b8ab4fd75ad0075dc6dc0be1745429d5a5c"
|
||||
integrity sha512-bY/7kg0LzRE7ytR0zRdSMWX3sknEjw68l836ffLPMh0OG3OYnNuBDUSF3v0vjvnzgYjgY9ZH/RypbARURlcMFA==
|
||||
dependencies:
|
||||
prosemirror-model "^1.20.0"
|
||||
prosemirror-state "^1.0.0"
|
||||
@@ -4355,32 +4412,32 @@ rfdc@^1.3.0, rfdc@^1.4.1:
|
||||
integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==
|
||||
|
||||
rollup@^4.20.0:
|
||||
version "4.40.2"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.40.2.tgz#778e88b7a197542682b3e318581f7697f55f0619"
|
||||
integrity sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==
|
||||
version "4.41.1"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.41.1.tgz#46ddc1b33cf1b0baa99320d3b0b4973dc2253b6a"
|
||||
integrity sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==
|
||||
dependencies:
|
||||
"@types/estree" "1.0.7"
|
||||
optionalDependencies:
|
||||
"@rollup/rollup-android-arm-eabi" "4.40.2"
|
||||
"@rollup/rollup-android-arm64" "4.40.2"
|
||||
"@rollup/rollup-darwin-arm64" "4.40.2"
|
||||
"@rollup/rollup-darwin-x64" "4.40.2"
|
||||
"@rollup/rollup-freebsd-arm64" "4.40.2"
|
||||
"@rollup/rollup-freebsd-x64" "4.40.2"
|
||||
"@rollup/rollup-linux-arm-gnueabihf" "4.40.2"
|
||||
"@rollup/rollup-linux-arm-musleabihf" "4.40.2"
|
||||
"@rollup/rollup-linux-arm64-gnu" "4.40.2"
|
||||
"@rollup/rollup-linux-arm64-musl" "4.40.2"
|
||||
"@rollup/rollup-linux-loongarch64-gnu" "4.40.2"
|
||||
"@rollup/rollup-linux-powerpc64le-gnu" "4.40.2"
|
||||
"@rollup/rollup-linux-riscv64-gnu" "4.40.2"
|
||||
"@rollup/rollup-linux-riscv64-musl" "4.40.2"
|
||||
"@rollup/rollup-linux-s390x-gnu" "4.40.2"
|
||||
"@rollup/rollup-linux-x64-gnu" "4.40.2"
|
||||
"@rollup/rollup-linux-x64-musl" "4.40.2"
|
||||
"@rollup/rollup-win32-arm64-msvc" "4.40.2"
|
||||
"@rollup/rollup-win32-ia32-msvc" "4.40.2"
|
||||
"@rollup/rollup-win32-x64-msvc" "4.40.2"
|
||||
"@rollup/rollup-android-arm-eabi" "4.41.1"
|
||||
"@rollup/rollup-android-arm64" "4.41.1"
|
||||
"@rollup/rollup-darwin-arm64" "4.41.1"
|
||||
"@rollup/rollup-darwin-x64" "4.41.1"
|
||||
"@rollup/rollup-freebsd-arm64" "4.41.1"
|
||||
"@rollup/rollup-freebsd-x64" "4.41.1"
|
||||
"@rollup/rollup-linux-arm-gnueabihf" "4.41.1"
|
||||
"@rollup/rollup-linux-arm-musleabihf" "4.41.1"
|
||||
"@rollup/rollup-linux-arm64-gnu" "4.41.1"
|
||||
"@rollup/rollup-linux-arm64-musl" "4.41.1"
|
||||
"@rollup/rollup-linux-loongarch64-gnu" "4.41.1"
|
||||
"@rollup/rollup-linux-powerpc64le-gnu" "4.41.1"
|
||||
"@rollup/rollup-linux-riscv64-gnu" "4.41.1"
|
||||
"@rollup/rollup-linux-riscv64-musl" "4.41.1"
|
||||
"@rollup/rollup-linux-s390x-gnu" "4.41.1"
|
||||
"@rollup/rollup-linux-x64-gnu" "4.41.1"
|
||||
"@rollup/rollup-linux-x64-musl" "4.41.1"
|
||||
"@rollup/rollup-win32-arm64-msvc" "4.41.1"
|
||||
"@rollup/rollup-win32-ia32-msvc" "4.41.1"
|
||||
"@rollup/rollup-win32-x64-msvc" "4.41.1"
|
||||
fsevents "~2.3.2"
|
||||
|
||||
rope-sequence@^1.3.0:
|
||||
@@ -4628,7 +4685,7 @@ sortablejs@1.14.0:
|
||||
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.14.0.tgz#6d2e17ccbdb25f464734df621d4f35d4ab35b3d8"
|
||||
integrity sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==
|
||||
|
||||
source-map-js@^1.2.0, source-map-js@^1.2.1:
|
||||
source-map-js@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
|
||||
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
|
||||
@@ -4914,10 +4971,10 @@ tinyexec@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.1.tgz#70c31ab7abbb4aea0a24f55d120e5990bfa1e0b1"
|
||||
integrity sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==
|
||||
|
||||
tinyglobby@^0.2.12:
|
||||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.13.tgz#a0e46515ce6cbcd65331537e57484af5a7b2ff7e"
|
||||
integrity sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==
|
||||
tinyglobby@^0.2.14:
|
||||
version "0.2.14"
|
||||
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d"
|
||||
integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==
|
||||
dependencies:
|
||||
fdir "^6.4.4"
|
||||
picomatch "^4.0.2"
|
||||
@@ -5104,23 +5161,23 @@ unplugin-utils@^0.2.4:
|
||||
picomatch "^4.0.2"
|
||||
|
||||
unplugin-vue-components@^28.4.1:
|
||||
version "28.5.0"
|
||||
resolved "https://registry.yarnpkg.com/unplugin-vue-components/-/unplugin-vue-components-28.5.0.tgz#33585a24c98939d1abe56bd69217bc7187ba329f"
|
||||
integrity sha512-o7fMKU/uI8NiP+E0W62zoduuguWqB0obTfHFtbr1AP2uo2lhUPnPttWUE92yesdiYfo9/0hxIrj38FMc1eaySg==
|
||||
version "28.7.0"
|
||||
resolved "https://registry.yarnpkg.com/unplugin-vue-components/-/unplugin-vue-components-28.7.0.tgz#e61e5a267a951fbace3190e0dfc61268a00f1b3a"
|
||||
integrity sha512-3SuWAHlTjOiZckqRBGXRdN/k6IMmKyt2Ch5/+DKwYaT321H0ItdZDvW4r8/YkEKQpN9TN3F/SZ0W342gQROC3Q==
|
||||
dependencies:
|
||||
chokidar "^3.6.0"
|
||||
debug "^4.4.0"
|
||||
debug "^4.4.1"
|
||||
local-pkg "^1.1.1"
|
||||
magic-string "^0.30.17"
|
||||
mlly "^1.7.4"
|
||||
tinyglobby "^0.2.12"
|
||||
unplugin "^2.3.2"
|
||||
tinyglobby "^0.2.14"
|
||||
unplugin "^2.3.4"
|
||||
unplugin-utils "^0.2.4"
|
||||
|
||||
unplugin@^2.2.0, unplugin@^2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-2.3.3.tgz#f83507e4484008e400f3d831a628eaede22c954f"
|
||||
integrity sha512-DN4DgiS13HFrAapoRmmoa9B35QzmQVRH2k58HelO28htXVNEEFZ8CGlZL0aRHXOXtz9McwY6lqaZjcc15uWMow==
|
||||
unplugin@^2.2.0, unplugin@^2.3.4:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-2.3.4.tgz#f3cf35f36656404cb9078be59f993941d649d87c"
|
||||
integrity sha512-m4PjxTurwpWfpMomp8AptjD5yj8qEZN5uQjjGM3TAs9MWWD2tXSSNNj6jGR2FoVGod4293ytyV6SwBbertfyJg==
|
||||
dependencies:
|
||||
acorn "^8.14.1"
|
||||
picomatch "^4.0.2"
|
||||
@@ -5278,15 +5335,15 @@ vue3-apexcharts@^1.8.0:
|
||||
integrity sha512-5tSD4mXTBbIJ9ir+58qHE6oNtIe0RNgqIRYMKpcsIaxkKtwUww4JhvPkpUFlmiW4OJbbdklgjleXq1lfcM4gdA==
|
||||
|
||||
vue@^3.3.0, vue@^3.4.23, vue@^3.5.13:
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.13.tgz#9f760a1a982b09c0c04a867903fc339c9f29ec0a"
|
||||
integrity sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==
|
||||
version "3.5.14"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.14.tgz#0ddf16d20cc20adaedfb5e77bca64c488bf5ee27"
|
||||
integrity sha512-LbOm50/vZFG6Mhy6KscQYXZMQ0LMCC/y40HDJPPvGFQ+i/lUH+PJHR6C3assgOQiXdl6tAfsXHbXYVBZZu65ew==
|
||||
dependencies:
|
||||
"@vue/compiler-dom" "3.5.13"
|
||||
"@vue/compiler-sfc" "3.5.13"
|
||||
"@vue/runtime-dom" "3.5.13"
|
||||
"@vue/server-renderer" "3.5.13"
|
||||
"@vue/shared" "3.5.13"
|
||||
"@vue/compiler-dom" "3.5.14"
|
||||
"@vue/compiler-sfc" "3.5.14"
|
||||
"@vue/runtime-dom" "3.5.14"
|
||||
"@vue/server-renderer" "3.5.14"
|
||||
"@vue/shared" "3.5.14"
|
||||
|
||||
vuedraggable@4.1.0:
|
||||
version "4.1.0"
|
||||
@@ -5459,9 +5516,9 @@ yallist@^2.1.2:
|
||||
integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==
|
||||
|
||||
yaml@^2.3.4, yaml@^2.7.1:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.7.1.tgz#44a247d1b88523855679ac7fa7cda6ed7e135cf6"
|
||||
integrity sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.0.tgz#15f8c9866211bdc2d3781a0890e44d4fa1a5fff6"
|
||||
integrity sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==
|
||||
|
||||
yargs-parser@^21.1.1:
|
||||
version "21.1.1"
|
||||
|
||||
Reference in New Issue
Block a user