refactor(ui): settings
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-y-auto">
|
||||
<SettingFields :fields="fields" :data="branding.data" />
|
||||
<SettingFields :sections="sections" :data="branding.data" />
|
||||
</div>
|
||||
<div class="flex flex-row-reverse mt-auto">
|
||||
<Button variant="solid" :loading="saveSettings.loading" @click="update">
|
||||
@@ -34,7 +34,7 @@ import { watch, ref } from 'vue'
|
||||
const isDirty = ref(false)
|
||||
|
||||
const props = defineProps({
|
||||
fields: {
|
||||
sections: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
<template>
|
||||
<div class="flex flex-col justify-between h-full text-base">
|
||||
<div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="text-xl font-semibold leading-none mb-2 text-ink-gray-9">
|
||||
{{ __(label) }}
|
||||
<div class="flex flex-col h-full text-base overflow-y-hidden">
|
||||
<div class="">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="text-xl font-semibold leading-none text-ink-gray-9">
|
||||
{{ __(label) }}
|
||||
</div>
|
||||
<Badge
|
||||
v-if="data.isDirty"
|
||||
:label="__('Not Saved')"
|
||||
variant="subtle"
|
||||
theme="orange"
|
||||
/>
|
||||
</div>
|
||||
<Badge
|
||||
v-if="data.isDirty"
|
||||
:label="__('Not Saved')"
|
||||
variant="subtle"
|
||||
theme="orange"
|
||||
/>
|
||||
<Button variant="solid" :loading="data.save.loading" @click="update">
|
||||
{{ __('Update') }}
|
||||
</Button>
|
||||
</div>
|
||||
<div class="text-ink-gray-6 leading-5">
|
||||
{{ __(description) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SettingFields :fields="fields" :data="data.doc" />
|
||||
<div class="flex flex-row-reverse mt-auto">
|
||||
<Button variant="solid" :loading="data.save.loading" @click="update">
|
||||
{{ __('Update') }}
|
||||
</Button>
|
||||
</div>
|
||||
<SettingFields :sections="sections" :data="data.doc" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -31,7 +31,7 @@ import { Button, Badge, toast } from 'frappe-ui'
|
||||
import SettingFields from '@/components/Settings/SettingFields.vue'
|
||||
|
||||
const props = defineProps({
|
||||
fields: {
|
||||
sections: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
@@ -49,13 +49,6 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const update = () => {
|
||||
props.fields.forEach((f) => {
|
||||
if (f.type == 'Upload') {
|
||||
props.data.doc[f.name] = f.value ? f.value.file_url : null
|
||||
} else if (f.type != 'Column Break') {
|
||||
props.data.doc[f.name] = f.value
|
||||
}
|
||||
})
|
||||
props.data.save.submit(
|
||||
{},
|
||||
{
|
||||
|
||||
@@ -1,115 +1,123 @@
|
||||
<template>
|
||||
<div
|
||||
class="my-5"
|
||||
:class="{ 'flex justify-between w-full': columns.length > 1 }"
|
||||
>
|
||||
<div v-for="(column, index) in columns" :key="index">
|
||||
<div class="mb-5 divide-y overflow-y-auto">
|
||||
<div v-for="(section, index) in sections" class="py-5">
|
||||
<div v-if="section.label" class="font-semibold text-ink-gray-9 mb-4">
|
||||
{{ section.label }}
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col space-y-5"
|
||||
:class="columns.length > 1 ? 'w-[21rem]' : 'w-full'"
|
||||
:class="{
|
||||
'flex justify-between space-x-8 w-full': section.columns.length > 1,
|
||||
}"
|
||||
>
|
||||
<div v-for="field in column">
|
||||
<Link
|
||||
v-if="field.type == 'Link'"
|
||||
v-model="data[field.name]"
|
||||
:doctype="field.doctype"
|
||||
:label="__(field.label)"
|
||||
:description="__(field.description)"
|
||||
/>
|
||||
|
||||
<div v-else-if="field.type == 'Code'">
|
||||
<CodeEditor
|
||||
:label="__(field.label)"
|
||||
type="HTML"
|
||||
description="The HTML you add here will be shown on your sign up page."
|
||||
<div
|
||||
v-for="(column, index) in section.columns"
|
||||
class="w-full space-y-5"
|
||||
>
|
||||
<div v-for="field in column.fields">
|
||||
<Link
|
||||
v-if="field.type == 'Link'"
|
||||
v-model="data[field.name]"
|
||||
height="250px"
|
||||
class="shrink-0"
|
||||
:showLineNumbers="true"
|
||||
>
|
||||
</CodeEditor>
|
||||
</div>
|
||||
:doctype="field.doctype"
|
||||
:label="__(field.label)"
|
||||
:description="__(field.description)"
|
||||
/>
|
||||
|
||||
<div v-else-if="field.type == 'Upload'">
|
||||
<div class="space-y-1 mb-2">
|
||||
<div class="text-sm text-ink-gray-5 font-medium">
|
||||
{{ __(field.label) }}
|
||||
</div>
|
||||
<div class="text-sm text-ink-gray-5 leading-5">
|
||||
{{ __(field.description) }}
|
||||
</div>
|
||||
</div>
|
||||
<FileUploader
|
||||
v-if="!data[field.name]"
|
||||
:fileTypes="['image/*']"
|
||||
:validateFile="validateFile"
|
||||
@success="(file) => (data[field.name] = file)"
|
||||
>
|
||||
<template
|
||||
v-slot="{ file, progress, uploading, openFileSelector }"
|
||||
<div v-else-if="field.type == 'Code'">
|
||||
<CodeEditor
|
||||
:label="__(field.label)"
|
||||
type="HTML"
|
||||
description="The HTML you add here will be shown on your sign up page."
|
||||
v-model="data[field.name]"
|
||||
height="250px"
|
||||
class="shrink-0"
|
||||
:showLineNumbers="true"
|
||||
>
|
||||
<div class="">
|
||||
<Button @click="openFileSelector" :loading="uploading">
|
||||
{{
|
||||
uploading ? `Uploading ${progress}%` : 'Upload an image'
|
||||
}}
|
||||
</Button>
|
||||
</CodeEditor>
|
||||
</div>
|
||||
|
||||
<div v-else-if="field.type == 'Upload'">
|
||||
<div class="space-y-1 mb-2">
|
||||
<div class="text-sm text-ink-gray-9 font-medium">
|
||||
{{ __(field.label) }}
|
||||
</div>
|
||||
</template>
|
||||
</FileUploader>
|
||||
<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-1 bg-surface-gray-2"
|
||||
:class="field.size == 'lg' ? 'px-5 py-5' : 'px-20 py-8'"
|
||||
<div class="text-sm text-ink-gray-5 leading-5">
|
||||
{{ __(field.description) }}
|
||||
</div>
|
||||
</div>
|
||||
<FileUploader
|
||||
v-if="!data[field.name]"
|
||||
:fileTypes="['image/*']"
|
||||
:validateFile="validateFile"
|
||||
@success="(file) => (data[field.name] = file)"
|
||||
>
|
||||
<template
|
||||
v-slot="{ file, progress, uploading, openFileSelector }"
|
||||
>
|
||||
<img
|
||||
:src="data[field.name]?.file_url || data[field.name]"
|
||||
class="rounded"
|
||||
:class="field.size == 'lg' ? 'w-36' : 'size-6'"
|
||||
<div class="">
|
||||
<Button @click="openFileSelector" :loading="uploading">
|
||||
{{
|
||||
uploading ? `Uploading ${progress}%` : 'Upload an image'
|
||||
}}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</FileUploader>
|
||||
<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-1 bg-surface-gray-2"
|
||||
:class="field.size == 'lg' ? 'px-5 py-5' : 'px-20 py-8'"
|
||||
>
|
||||
<img
|
||||
:src="data[field.name]?.file_url || data[field.name]"
|
||||
class="rounded"
|
||||
:class="field.size == 'lg' ? 'w-36' : 'size-6'"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col flex-wrap">
|
||||
<span class="break-all text-ink-gray-9">
|
||||
{{
|
||||
data[field.name]?.file_name ||
|
||||
data[field.name].split('/').pop()
|
||||
}}
|
||||
</span>
|
||||
<span
|
||||
v-if="data[field.name]?.file_size"
|
||||
class="text-sm text-ink-gray-5 mt-1"
|
||||
>
|
||||
{{ getFileSize(data[field.name]?.file_size) }}
|
||||
</span>
|
||||
</div>
|
||||
<X
|
||||
@click="data[field.name] = null"
|
||||
class="border text-ink-gray-7 border-outline-gray-3 rounded-md cursor-pointer stroke-1.5 w-5 h-5 p-1 ml-4"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col flex-wrap">
|
||||
<span class="break-all text-ink-gray-9">
|
||||
{{
|
||||
data[field.name]?.file_name ||
|
||||
data[field.name].split('/').pop()
|
||||
}}
|
||||
</span>
|
||||
<span
|
||||
v-if="data[field.name]?.file_size"
|
||||
class="text-sm text-ink-gray-5 mt-1"
|
||||
>
|
||||
{{ getFileSize(data[field.name]?.file_size) }}
|
||||
</span>
|
||||
</div>
|
||||
<X
|
||||
@click="data[field.name] = null"
|
||||
class="border text-ink-gray-7 border-outline-gray-3 rounded-md cursor-pointer stroke-1.5 w-5 h-5 p-1 ml-4"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
v-else-if="field.type == 'checkbox'"
|
||||
size="sm"
|
||||
:label="__(field.label)"
|
||||
:description="__(field.description)"
|
||||
v-model="field.value"
|
||||
/>
|
||||
<!-- <div v-else>
|
||||
{{ data[field.name] }}
|
||||
|
||||
</div> -->
|
||||
<FormControl
|
||||
v-else
|
||||
:key="field.name"
|
||||
v-model="data[field.name]"
|
||||
:label="__(field.label)"
|
||||
:type="field.type"
|
||||
:rows="field.rows"
|
||||
:options="field.options"
|
||||
:description="field.description"
|
||||
placeholder=""
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Switch
|
||||
v-else-if="field.type == 'checkbox'"
|
||||
size="sm"
|
||||
:label="__(field.label)"
|
||||
:description="__(field.description)"
|
||||
v-model="field.value"
|
||||
/>
|
||||
|
||||
<FormControl
|
||||
v-else
|
||||
:key="field.name"
|
||||
v-model="data[field.name]"
|
||||
:label="__(field.label)"
|
||||
:type="field.type"
|
||||
:rows="field.rows"
|
||||
:options="field.options"
|
||||
:description="field.description"
|
||||
:class="columns.length > 1 ? 'w-full' : 'w-1/2'"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -117,14 +125,14 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import { FormControl, FileUploader, Button, Switch } from 'frappe-ui'
|
||||
import { computed } from 'vue'
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { getFileSize, validateFile } from '@/utils'
|
||||
import { X } from 'lucide-vue-next'
|
||||
import Link from '@/components/Controls/Link.vue'
|
||||
import CodeEditor from '@/components/Controls/CodeEditor.vue'
|
||||
|
||||
const props = defineProps({
|
||||
fields: {
|
||||
sections: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
@@ -134,30 +142,34 @@ const props = defineProps({
|
||||
},
|
||||
})
|
||||
|
||||
const columns = computed(() => {
|
||||
const cols = []
|
||||
let currentColumn = []
|
||||
|
||||
props.fields.forEach((field) => {
|
||||
if (field.type === 'Column Break') {
|
||||
if (currentColumn.length > 0) {
|
||||
cols.push(currentColumn)
|
||||
currentColumn = []
|
||||
}
|
||||
} else {
|
||||
if (field.type == 'checkbox') {
|
||||
field.value = props.data[field.name] ? true : false
|
||||
} else {
|
||||
field.value = props.data[field.name]
|
||||
}
|
||||
currentColumn.push(field)
|
||||
}
|
||||
onMounted(() => {
|
||||
props.sections.forEach((section) => {
|
||||
section.columns.forEach((column) => {
|
||||
column.fields.forEach((field) => {
|
||||
if (field.type == 'checkbox') {
|
||||
field.value = props.data[field.name] ? true : false
|
||||
} else {
|
||||
field.value = props.data[field.name]
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
if (currentColumn.length > 0) {
|
||||
cols.push(currentColumn)
|
||||
}
|
||||
|
||||
return cols
|
||||
})
|
||||
|
||||
watch(
|
||||
props.sections,
|
||||
(newSections) => {
|
||||
// Makes the form dirty on change
|
||||
newSections.forEach((section) => {
|
||||
section.columns.forEach((column) => {
|
||||
column.fields.forEach((field) => {
|
||||
if (props.data[field.name] != field.value) {
|
||||
props.data[field.name] = field.value
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div v-for="tab in tabs" :key="tab.label">
|
||||
<div
|
||||
v-if="!tab.hideLabel"
|
||||
class="mb-2 mt-3 flex cursor-pointer gap-1.5 px-1 text-base font-medium text-ink-gray-5 transition-all duration-300 ease-in-out"
|
||||
class="mb-2 mt-3 flex cursor-pointer gap-1.5 px-1 text-base text-ink-gray-5 transition-all duration-300 ease-in-out"
|
||||
>
|
||||
<span>{{ __(tab.label) }}</span>
|
||||
</div>
|
||||
@@ -38,7 +38,7 @@
|
||||
label: activeTab.label,
|
||||
description: activeTab.description,
|
||||
...(activeTab.label == 'Branding'
|
||||
? { fields: activeTab.fields }
|
||||
? { sections: activeTab.sections }
|
||||
: {}),
|
||||
...(activeTab.label == 'Evaluators' ||
|
||||
activeTab.label == 'Members' ||
|
||||
@@ -47,16 +47,9 @@
|
||||
: {}),
|
||||
}"
|
||||
/>
|
||||
<!-- <PaymentSettings
|
||||
v-else-if="activeTab.label === 'Gateways'"
|
||||
:label="activeTab.label"
|
||||
:description="activeTab.description"
|
||||
:data="data"
|
||||
:fields="activeTab.fields"
|
||||
/> -->
|
||||
<SettingDetails
|
||||
v-else
|
||||
:fields="activeTab.fields"
|
||||
:sections="activeTab.sections"
|
||||
:label="activeTab.label"
|
||||
:description="activeTab.description"
|
||||
:data="data"
|
||||
@@ -99,90 +92,158 @@ const data = createDocumentResource({
|
||||
const tabsStructure = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: 'Settings',
|
||||
label: 'Configuration',
|
||||
hideLabel: true,
|
||||
items: [
|
||||
{
|
||||
label: 'General',
|
||||
icon: 'Wrench',
|
||||
fields: [
|
||||
sections: [
|
||||
{
|
||||
label: 'Allow Guest Access',
|
||||
name: 'allow_guest_access',
|
||||
description:
|
||||
'If enabled, users can access the course and batch lists without logging in.',
|
||||
type: 'checkbox',
|
||||
label: 'System Configurations',
|
||||
columns: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Allow Guest Access',
|
||||
name: 'allow_guest_access',
|
||||
description:
|
||||
'If enabled, users can access the course and batch lists without logging in.',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Prevent Skipping Videos',
|
||||
name: 'prevent_skipping_videos',
|
||||
type: 'checkbox',
|
||||
description:
|
||||
'If enabled, users will no able to move forward in a video',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Disable PWA',
|
||||
name: 'disable_pwa',
|
||||
type: 'checkbox',
|
||||
description:
|
||||
'If checked, users will not be able to install the application as a Progressive Web App.',
|
||||
},
|
||||
{
|
||||
label: 'Send calendar invite for evaluations',
|
||||
name: 'send_calendar_invite_for_evaluations',
|
||||
description:
|
||||
'If enabled, it sends google calendar invite to the student for evaluations.',
|
||||
type: 'checkbox',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Prevent Skipping Videos',
|
||||
name: 'prevent_skipping_videos',
|
||||
type: 'checkbox',
|
||||
description:
|
||||
'If enabled, users will no able to move forward in a video',
|
||||
label: 'Notifications',
|
||||
columns: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Send Notification for Published Courses',
|
||||
name: 'send_notification_for_published_courses',
|
||||
type: 'select',
|
||||
options: [' ', 'Email', 'In-app'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Send Notification for Published Batches',
|
||||
name: 'send_notification_for_published_batches',
|
||||
type: 'select',
|
||||
options: [' ', 'Email', 'In-app'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Disable PWA',
|
||||
name: 'disable_pwa',
|
||||
type: 'checkbox',
|
||||
description:
|
||||
'If checked, users will not be able to install the application as a Progressive Web App.',
|
||||
label: 'Email Templates',
|
||||
columns: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Batch Confirmation Email Template',
|
||||
name: 'batch_confirmation_template',
|
||||
doctype: 'Email Template',
|
||||
type: 'Link',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Certification Email Template',
|
||||
name: 'certification_template',
|
||||
doctype: 'Email Template',
|
||||
type: 'Link',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Send calendar invite for evaluations',
|
||||
name: 'send_calendar_invite_for_evaluations',
|
||||
description:
|
||||
'If enabled, it sends google calendar invite to the student for evaluations.',
|
||||
type: 'checkbox',
|
||||
label: 'Contact Information',
|
||||
columns: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Email',
|
||||
name: 'contact_us_email',
|
||||
type: 'text',
|
||||
description:
|
||||
'Users can reach out to this email for support or inquiries.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'URL',
|
||||
name: 'contact_us_url',
|
||||
type: 'text',
|
||||
description:
|
||||
'Users can reach out to this URL for support or inquiries.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'Column Break',
|
||||
},
|
||||
{
|
||||
label: 'Livecode URL',
|
||||
name: 'livecode_url',
|
||||
doctype: 'Livecode URL',
|
||||
type: 'text',
|
||||
description:
|
||||
'https://docs.frappe.io/learning/falcon-self-hosting-guide',
|
||||
},
|
||||
{
|
||||
label: 'Batch Confirmation Email Template',
|
||||
name: 'batch_confirmation_template',
|
||||
doctype: 'Email Template',
|
||||
type: 'Link',
|
||||
},
|
||||
{
|
||||
label: 'Certification Email Template',
|
||||
name: 'certification_template',
|
||||
doctype: 'Email Template',
|
||||
type: 'Link',
|
||||
},
|
||||
{
|
||||
label: 'Unsplash Access Key',
|
||||
name: 'unsplash_access_key',
|
||||
description:
|
||||
'Allows users to pick a profile cover image from Unsplash. https://unsplash.com/documentation#getting-started.',
|
||||
type: 'password',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Contact Us',
|
||||
icon: 'Phone',
|
||||
fields: [
|
||||
{
|
||||
label: 'Email',
|
||||
name: 'contact_us_email',
|
||||
type: 'text',
|
||||
description:
|
||||
'Users can reach out to this email for support or inquiries.',
|
||||
},
|
||||
{
|
||||
label: 'URL',
|
||||
name: 'contact_us_url',
|
||||
type: 'text',
|
||||
description:
|
||||
'Users can reach out to this URL for support or inquiries.',
|
||||
label: '',
|
||||
columns: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Livecode URL',
|
||||
name: 'livecode_url',
|
||||
doctype: 'Livecode URL',
|
||||
type: 'text',
|
||||
description:
|
||||
'https://docs.frappe.io/learning/falcon-self-hosting-guide',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Unsplash Access Key',
|
||||
name: 'unsplash_access_key',
|
||||
description:
|
||||
'Allows users to pick a profile cover image from Unsplash. https://unsplash.com/documentation#getting-started.',
|
||||
type: 'password',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -243,36 +304,45 @@ const tabsStructure = computed(() => {
|
||||
label: 'Configuration',
|
||||
icon: 'CreditCard',
|
||||
description: 'Manage all your payment related settings and defaults',
|
||||
fields: [
|
||||
sections: [
|
||||
{
|
||||
label: 'Default Currency',
|
||||
name: 'default_currency',
|
||||
type: 'Link',
|
||||
doctype: 'Currency',
|
||||
},
|
||||
{
|
||||
label: 'Payment Gateway',
|
||||
name: 'payment_gateway',
|
||||
type: 'Link',
|
||||
doctype: 'Payment Gateway',
|
||||
},
|
||||
{
|
||||
type: 'Column Break',
|
||||
},
|
||||
{
|
||||
label: 'Apply GST for India',
|
||||
name: 'apply_gst',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Show USD equivalent amount',
|
||||
name: 'show_usd_equivalent',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Apply rounding on equivalent',
|
||||
name: 'apply_rounding',
|
||||
type: 'checkbox',
|
||||
columns: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Default Currency',
|
||||
name: 'default_currency',
|
||||
type: 'Link',
|
||||
doctype: 'Currency',
|
||||
},
|
||||
{
|
||||
label: 'Payment Gateway',
|
||||
name: 'payment_gateway',
|
||||
type: 'Link',
|
||||
doctype: 'Payment Gateway',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Apply GST for India',
|
||||
name: 'apply_gst',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Show USD equivalent amount',
|
||||
name: 'show_usd_equivalent',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Apply rounding on equivalent',
|
||||
name: 'apply_rounding',
|
||||
type: 'checkbox',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -304,25 +374,33 @@ const tabsStructure = computed(() => {
|
||||
label: 'Branding',
|
||||
icon: 'Blocks',
|
||||
template: markRaw(BrandSettings),
|
||||
fields: [
|
||||
sections: [
|
||||
{
|
||||
label: 'Brand Name',
|
||||
name: 'app_name',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
label: 'Logo',
|
||||
name: 'banner_image',
|
||||
type: 'Upload',
|
||||
description:
|
||||
'Appears in the top left corner of the application to represent your brand.',
|
||||
},
|
||||
{
|
||||
label: 'Favicon',
|
||||
name: 'favicon',
|
||||
type: 'Upload',
|
||||
description:
|
||||
'Appears in the browser tab next to the page title to help users quickly identify the application.',
|
||||
columns: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Brand Name',
|
||||
name: 'app_name',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
label: 'Logo',
|
||||
name: 'banner_image',
|
||||
type: 'Upload',
|
||||
description:
|
||||
'Appears in the top left corner of the application to represent your brand.',
|
||||
},
|
||||
{
|
||||
label: 'Favicon',
|
||||
name: 'favicon',
|
||||
type: 'Upload',
|
||||
description:
|
||||
'Appears in the browser tab next to the page title to help users quickly identify the application.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -330,105 +408,124 @@ const tabsStructure = computed(() => {
|
||||
label: 'Sidebar',
|
||||
icon: 'PanelLeftIcon',
|
||||
description: 'Choose the items you want to show in the sidebar',
|
||||
fields: [
|
||||
sections: [
|
||||
{
|
||||
label: 'Courses',
|
||||
name: 'courses',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Batches',
|
||||
name: 'batches',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Programming Exercises',
|
||||
name: 'programming_exercises',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Certifications',
|
||||
name: 'certifications',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
type: 'Column Break',
|
||||
},
|
||||
{
|
||||
label: 'Jobs',
|
||||
name: 'jobs',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Statistics',
|
||||
name: 'statistics',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Notifications',
|
||||
name: 'notifications',
|
||||
type: 'checkbox',
|
||||
columns: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Courses',
|
||||
name: 'courses',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Batches',
|
||||
name: 'batches',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Programming Exercises',
|
||||
name: 'programming_exercises',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Certifications',
|
||||
name: 'certifications',
|
||||
type: 'checkbox',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Jobs',
|
||||
name: 'jobs',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Statistics',
|
||||
name: 'statistics',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
label: 'Notifications',
|
||||
name: 'notifications',
|
||||
type: 'checkbox',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Signup',
|
||||
icon: 'LogIn',
|
||||
fields: [
|
||||
sections: [
|
||||
{
|
||||
label: 'Identify User Category',
|
||||
name: 'user_category',
|
||||
type: 'checkbox',
|
||||
description:
|
||||
'Enable this option to identify the user category during signup.',
|
||||
},
|
||||
{
|
||||
label: 'Disable signup',
|
||||
name: 'disable_signup',
|
||||
type: 'checkbox',
|
||||
description:
|
||||
'New users will have to be manually registered by Admins.',
|
||||
},
|
||||
{
|
||||
type: 'Column Break',
|
||||
},
|
||||
{
|
||||
label: 'Signup Consent HTML',
|
||||
name: 'custom_signup_content',
|
||||
type: 'Code',
|
||||
mode: 'htmlmixed',
|
||||
rows: 10,
|
||||
columns: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Identify User Category',
|
||||
name: 'user_category',
|
||||
type: 'checkbox',
|
||||
description:
|
||||
'Enable this option to identify the user category during signup.',
|
||||
},
|
||||
{
|
||||
label: 'Disable signup',
|
||||
name: 'disable_signup',
|
||||
type: 'checkbox',
|
||||
description:
|
||||
'New users will have to be manually registered by Admins.',
|
||||
},
|
||||
{
|
||||
label: 'Signup Consent HTML',
|
||||
name: 'custom_signup_content',
|
||||
type: 'Code',
|
||||
mode: 'htmlmixed',
|
||||
rows: 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'SEO',
|
||||
icon: 'Search',
|
||||
fields: [
|
||||
sections: [
|
||||
{
|
||||
label: 'Meta Description',
|
||||
name: 'meta_description',
|
||||
type: 'textarea',
|
||||
rows: 4,
|
||||
description:
|
||||
"This description will be shown on lists and pages that don't have meta description",
|
||||
},
|
||||
{
|
||||
label: 'Meta Keywords',
|
||||
name: 'meta_keywords',
|
||||
type: 'textarea',
|
||||
rows: 4,
|
||||
description:
|
||||
'Comma separated keywords for search engines to find your website.',
|
||||
},
|
||||
{
|
||||
type: 'Column Break',
|
||||
},
|
||||
{
|
||||
label: 'Meta Image',
|
||||
name: 'meta_image',
|
||||
type: 'Upload',
|
||||
size: 'lg',
|
||||
columns: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
label: 'Meta Description',
|
||||
name: 'meta_description',
|
||||
type: 'textarea',
|
||||
rows: 4,
|
||||
description:
|
||||
"This description will be shown on lists and pages that don't have meta description",
|
||||
},
|
||||
{
|
||||
label: 'Meta Keywords',
|
||||
name: 'meta_keywords',
|
||||
type: 'textarea',
|
||||
rows: 4,
|
||||
description:
|
||||
'Comma separated keywords for search engines to find your website.',
|
||||
},
|
||||
{
|
||||
label: 'Meta Image',
|
||||
name: 'meta_image',
|
||||
type: 'Upload',
|
||||
size: 'lg',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -6,16 +6,20 @@
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"general_tab",
|
||||
"default_home",
|
||||
"send_calendar_invite_for_evaluations",
|
||||
"persona_captured",
|
||||
"column_break_zdel",
|
||||
"allow_guest_access",
|
||||
"prevent_skipping_videos",
|
||||
"send_calendar_invite_for_evaluations",
|
||||
"column_break_zdel",
|
||||
"disable_pwa",
|
||||
"persona_captured",
|
||||
"default_home",
|
||||
"column_break_bjis",
|
||||
"unsplash_access_key",
|
||||
"livecode_url",
|
||||
"notifications_section",
|
||||
"send_notification_for_published_courses",
|
||||
"column_break_dtns",
|
||||
"send_notification_for_published_batches",
|
||||
"section_break_szgq",
|
||||
"show_day_view",
|
||||
"column_break_2",
|
||||
@@ -446,13 +450,34 @@
|
||||
"fieldname": "disable_pwa",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disable PWA"
|
||||
},
|
||||
{
|
||||
"fieldname": "send_notification_for_published_courses",
|
||||
"fieldtype": "Select",
|
||||
"label": "Send Notification for Published Courses",
|
||||
"options": "\nEmail\nIn-app"
|
||||
},
|
||||
{
|
||||
"fieldname": "send_notification_for_published_batches",
|
||||
"fieldtype": "Select",
|
||||
"label": "Send Notification for Published Batches",
|
||||
"options": "\nEmail\nIn-app"
|
||||
},
|
||||
{
|
||||
"fieldname": "notifications_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Notifications"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_dtns",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2025-12-22 11:30:13.868031",
|
||||
"modified": "2026-01-01 19:36:54.443390",
|
||||
"modified_by": "sayali@frappe.io",
|
||||
"module": "LMS",
|
||||
"name": "LMS Settings",
|
||||
|
||||
Reference in New Issue
Block a user