Merge pull request #1057 from pateljannat/settings-minor-changes
fix: misc ux issues
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
"@editorjs/nested-list": "^1.4.2",
|
"@editorjs/nested-list": "^1.4.2",
|
||||||
"@editorjs/paragraph": "^2.11.3",
|
"@editorjs/paragraph": "^2.11.3",
|
||||||
"@editorjs/simple-image": "^1.6.0",
|
"@editorjs/simple-image": "^1.6.0",
|
||||||
|
"ace-builds": "^1.36.2",
|
||||||
"chart.js": "^4.4.1",
|
"chart.js": "^4.4.1",
|
||||||
"codemirror-editor-vue3": "^2.8.0",
|
"codemirror-editor-vue3": "^2.8.0",
|
||||||
"dayjs": "^1.11.6",
|
"dayjs": "^1.11.6",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col justify-between h-full">
|
<div class="flex flex-col justify-between min-h-0">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="font-semibold mb-1">
|
<div class="font-semibold mb-1">
|
||||||
@@ -16,11 +16,13 @@
|
|||||||
{{ __(description) }}
|
{{ __(description) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<SettingFields :fields="fields" :data="data.data" />
|
<div class="overflow-y-auto">
|
||||||
<div class="flex flex-row-reverse mt-auto">
|
<SettingFields :fields="fields" :data="data.data" />
|
||||||
<Button variant="solid" :loading="saveSettings.loading" @click="update">
|
<div class="flex flex-row-reverse mt-auto">
|
||||||
{{ __('Update') }}
|
<Button variant="solid" :loading="saveSettings.loading" @click="update">
|
||||||
</Button>
|
{{ __('Update') }}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -70,12 +72,20 @@ const update = () => {
|
|||||||
fieldsToSave[f.name] = f.value
|
fieldsToSave[f.name] = f.value
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
saveSettings.submit({
|
saveSettings.submit(
|
||||||
fields: fieldsToSave,
|
{
|
||||||
})
|
fields: fieldsToSave,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess(data) {
|
||||||
|
isDirty.value = false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(props.data, (newData) => {
|
watch(props.data, (newData) => {
|
||||||
|
console.log(newData)
|
||||||
if (newData && !isDirty.value) {
|
if (newData && !isDirty.value) {
|
||||||
isDirty.value = true
|
isDirty.value = true
|
||||||
}
|
}
|
||||||
|
|||||||
204
frontend/src/components/Controls/CodeEditor.vue
Normal file
204
frontend/src/components/Controls/CodeEditor.vue
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="editor flex flex-col gap-1"
|
||||||
|
:style="{
|
||||||
|
height: height,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<span class="text-xs" v-if="label">
|
||||||
|
{{ label }}
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
ref="editor"
|
||||||
|
class="h-auto flex-1 overflow-hidden overscroll-none !rounded border border-outline-gray-2 bg-surface-gray-2 dark:bg-gray-900"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="mt-1 text-xs text-gray-600"
|
||||||
|
v-show="description"
|
||||||
|
v-html="description"
|
||||||
|
></span>
|
||||||
|
<Button
|
||||||
|
v-if="showSaveButton"
|
||||||
|
@click="emit('save', aceEditor?.getValue())"
|
||||||
|
class="mt-3"
|
||||||
|
>
|
||||||
|
{{ __('Save') }}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useDark } from '@vueuse/core'
|
||||||
|
import ace from 'ace-builds'
|
||||||
|
import 'ace-builds/src-min-noconflict/ext-searchbox'
|
||||||
|
import 'ace-builds/src-min-noconflict/theme-chrome'
|
||||||
|
import 'ace-builds/src-min-noconflict/theme-twilight'
|
||||||
|
import { PropType, onMounted, ref, watch } from 'vue'
|
||||||
|
import { Button } from 'frappe-ui'
|
||||||
|
|
||||||
|
const isDark = useDark({
|
||||||
|
attribute: 'data-theme',
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: [Object, String, Array],
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String as PropType<'JSON' | 'HTML' | 'Python' | 'JavaScript' | 'CSS'>,
|
||||||
|
default: 'JSON',
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
readonly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '250px',
|
||||||
|
},
|
||||||
|
showLineNumbers: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
autofocus: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
showSaveButton: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['save', 'update:modelValue'])
|
||||||
|
const editor = ref<HTMLElement | null>(null)
|
||||||
|
let aceEditor = null as ace.Ace.Editor | null
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setupEditor()
|
||||||
|
})
|
||||||
|
|
||||||
|
const setupEditor = () => {
|
||||||
|
aceEditor = ace.edit(editor.value as HTMLElement)
|
||||||
|
resetEditor(props.modelValue as string, true)
|
||||||
|
aceEditor.setReadOnly(props.readonly)
|
||||||
|
aceEditor.setOptions({
|
||||||
|
fontSize: '12px',
|
||||||
|
useWorker: false,
|
||||||
|
showGutter: props.showLineNumbers,
|
||||||
|
wrap: props.showLineNumbers,
|
||||||
|
})
|
||||||
|
if (props.type === 'CSS') {
|
||||||
|
import('ace-builds/src-noconflict/mode-css').then(() => {
|
||||||
|
aceEditor?.session.setMode('ace/mode/css')
|
||||||
|
})
|
||||||
|
} else if (props.type === 'JavaScript') {
|
||||||
|
import('ace-builds/src-noconflict/mode-javascript').then(() => {
|
||||||
|
aceEditor?.session.setMode('ace/mode/javascript')
|
||||||
|
})
|
||||||
|
} else if (props.type === 'Python') {
|
||||||
|
import('ace-builds/src-noconflict/mode-python').then(() => {
|
||||||
|
aceEditor?.session.setMode('ace/mode/python')
|
||||||
|
})
|
||||||
|
} else if (props.type === 'JSON') {
|
||||||
|
import('ace-builds/src-noconflict/mode-json').then(() => {
|
||||||
|
aceEditor?.session.setMode('ace/mode/json')
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
import('ace-builds/src-noconflict/mode-html').then(() => {
|
||||||
|
aceEditor?.session.setMode('ace/mode/html')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
aceEditor.on('blur', () => {
|
||||||
|
try {
|
||||||
|
let value = aceEditor?.getValue() || ''
|
||||||
|
if (props.type === 'JSON') {
|
||||||
|
value = JSON.parse(value)
|
||||||
|
}
|
||||||
|
if (value === props.modelValue) return
|
||||||
|
if (!props.showSaveButton && !props.readonly) {
|
||||||
|
emit('update:modelValue', value)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getModelValue = () => {
|
||||||
|
let value = props.modelValue || ''
|
||||||
|
try {
|
||||||
|
if (props.type === 'JSON' || typeof value === 'object') {
|
||||||
|
value = JSON.stringify(value, null, 2)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
return value as string
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetEditor(value: string, resetHistory = false) {
|
||||||
|
value = getModelValue()
|
||||||
|
aceEditor?.setValue(value)
|
||||||
|
aceEditor?.clearSelection()
|
||||||
|
aceEditor?.setTheme(isDark.value ? 'ace/theme/twilight' : 'ace/theme/chrome')
|
||||||
|
props.autofocus && aceEditor?.focus()
|
||||||
|
if (resetHistory) {
|
||||||
|
aceEditor?.session.getUndoManager().reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(isDark, () => {
|
||||||
|
aceEditor?.setTheme(isDark.value ? 'ace/theme/twilight' : 'ace/theme/chrome')
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.type,
|
||||||
|
() => {
|
||||||
|
setupEditor()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
() => {
|
||||||
|
resetEditor(props.modelValue as string)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
defineExpose({ resetEditor })
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.editor .ace_editor {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 5px;
|
||||||
|
overscroll-behavior: none;
|
||||||
|
}
|
||||||
|
.editor :deep(.ace_scrollbar-h) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.editor :deep(.ace_search) {
|
||||||
|
@apply dark:bg-gray-800 dark:text-gray-200;
|
||||||
|
@apply dark:border-gray-800;
|
||||||
|
}
|
||||||
|
.editor :deep(.ace_searchbtn) {
|
||||||
|
@apply dark:bg-gray-800 dark:text-gray-200;
|
||||||
|
@apply dark:border-gray-800;
|
||||||
|
}
|
||||||
|
.editor :deep(.ace_button) {
|
||||||
|
@apply dark:bg-gray-800 dark:text-gray-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor :deep(.ace_search_field) {
|
||||||
|
@apply dark:bg-gray-900 dark:text-gray-200;
|
||||||
|
@apply dark:border-gray-800;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -116,7 +116,7 @@
|
|||||||
import { BookOpen, Users, Star } from 'lucide-vue-next'
|
import { BookOpen, Users, Star } from 'lucide-vue-next'
|
||||||
import { computed, inject } from 'vue'
|
import { computed, inject } from 'vue'
|
||||||
import { Button, createResource } from 'frappe-ui'
|
import { Button, createResource } from 'frappe-ui'
|
||||||
import { createToast } from '@/utils/'
|
import { showToast } from '@/utils/'
|
||||||
import { capture } from '@/telemetry'
|
import { capture } from '@/telemetry'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
@@ -139,11 +139,11 @@ const video_link = computed(() => {
|
|||||||
|
|
||||||
function enrollStudent() {
|
function enrollStudent() {
|
||||||
if (!user.data) {
|
if (!user.data) {
|
||||||
createToast({
|
showToast(
|
||||||
title: 'Please Login',
|
__('Please Login'),
|
||||||
icon: 'alert-circle',
|
__('You need to login first to enroll for this course'),
|
||||||
iconClasses: 'text-yellow-600 bg-yellow-100',
|
'circle-warn'
|
||||||
})
|
)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.href = `/login?redirect-to=${window.location.pathname}`
|
window.location.href = `/login?redirect-to=${window.location.pathname}`
|
||||||
}, 2000)
|
}, 2000)
|
||||||
@@ -159,11 +159,11 @@ function enrollStudent() {
|
|||||||
capture('enrolled_in_course', {
|
capture('enrolled_in_course', {
|
||||||
course: props.course.data.name,
|
course: props.course.data.name,
|
||||||
})
|
})
|
||||||
createToast({
|
showToast(
|
||||||
title: 'Enrolled Successfully',
|
__('Success'),
|
||||||
icon: 'check',
|
__('You have been enrolled in this course'),
|
||||||
iconClasses: 'text-green-600 bg-green-100',
|
'check'
|
||||||
})
|
)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
router.push({
|
router.push({
|
||||||
name: 'Lesson',
|
name: 'Lesson',
|
||||||
@@ -173,7 +173,7 @@ function enrollStudent() {
|
|||||||
lessonNumber: 1,
|
lessonNumber: 1,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}, 3000)
|
}, 2000)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,26 +179,6 @@ const tabsStructure = computed(() => {
|
|||||||
name: 'app_name',
|
name: 'app_name',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Copyright',
|
|
||||||
name: 'copyright',
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Address',
|
|
||||||
name: 'address',
|
|
||||||
type: 'textarea',
|
|
||||||
rows: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Footer "Powered By"',
|
|
||||||
name: 'footer_powered',
|
|
||||||
type: 'textarea',
|
|
||||||
rows: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'Column Break',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Logo',
|
label: 'Logo',
|
||||||
name: 'banner_image',
|
name: 'banner_image',
|
||||||
@@ -214,6 +194,23 @@ const tabsStructure = computed(() => {
|
|||||||
name: 'footer_logo',
|
name: 'footer_logo',
|
||||||
type: 'Upload',
|
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',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -292,9 +289,11 @@ const tabsStructure = computed(() => {
|
|||||||
rows: 10,
|
rows: 10,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Ask user category',
|
label: 'Ask for Occupation',
|
||||||
name: 'user_category',
|
name: 'user_category',
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
|
description:
|
||||||
|
'Enable this option to ask users to select their occupation during the signup process.',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="flex flex-col justify-between h-full">
|
<div class="flex flex-col justify-between h-full">
|
||||||
<div>
|
<div>
|
||||||
<div class="flex itemsc-center justify-between">
|
<div class="flex itemsc-center justify-between">
|
||||||
<div class="font-semibold mb-1">
|
<div class="text-xl font-semibold leading-none mb-1">
|
||||||
{{ __(label) }}
|
{{ __(label) }}
|
||||||
</div>
|
</div>
|
||||||
<Badge
|
<Badge
|
||||||
|
|||||||
@@ -17,17 +17,16 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div v-else-if="field.type == 'Code'">
|
<div v-else-if="field.type == 'Code'">
|
||||||
<div>
|
<CodeEditor
|
||||||
{{ __(field.label) }}
|
:label="__(field.label)"
|
||||||
</div>
|
type="HTML"
|
||||||
<Codemirror
|
description="The HTML you add here will be shown on your sign up page."
|
||||||
v-model:value="data[field.name]"
|
v-model="data[field.name]"
|
||||||
:height="200"
|
height="250px"
|
||||||
:options="{
|
class="shrink-0"
|
||||||
mode: field.mode,
|
:showLineNumbers="true"
|
||||||
theme: 'seti',
|
>
|
||||||
}"
|
</CodeEditor>
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="field.type == 'Upload'">
|
<div v-else-if="field.type == 'Upload'">
|
||||||
@@ -53,9 +52,11 @@
|
|||||||
</template>
|
</template>
|
||||||
</FileUploader>
|
</FileUploader>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="flex items-center text-sm">
|
<div class="flex items-center text-sm space-x-2">
|
||||||
<div class="border rounded-md p-2 mr-2">
|
<div
|
||||||
<FileText class="h-5 w-5 stroke-1.5 text-gray-700" />
|
class="flex items-center justify-center rounded border border-outline-gray-1 w-[15rem] py-5"
|
||||||
|
>
|
||||||
|
<img :src="data[field.name]?.file_url" class="h-6 rounded" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col flex-wrap">
|
<div class="flex flex-col flex-wrap">
|
||||||
<span class="break-all">
|
<span class="break-all">
|
||||||
@@ -73,6 +74,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
v-else-if="field.type == 'checkbox'"
|
||||||
|
size="sm"
|
||||||
|
:label="__(field.label)"
|
||||||
|
:description="__(field.description)"
|
||||||
|
v-model="data[field.name]"
|
||||||
|
/>
|
||||||
|
|
||||||
<FormControl
|
<FormControl
|
||||||
v-else
|
v-else
|
||||||
:key="field.name"
|
:key="field.name"
|
||||||
@@ -88,14 +97,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { FormControl, FileUploader, Button } from 'frappe-ui'
|
import { FormControl, FileUploader, Button, Switch } from 'frappe-ui'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { getFileSize, validateFile } from '@/utils'
|
import { getFileSize, validateFile } from '@/utils'
|
||||||
import { X, FileText } from 'lucide-vue-next'
|
import { X, FileText } from 'lucide-vue-next'
|
||||||
import Link from '@/components/Controls/Link.vue'
|
import Link from '@/components/Controls/Link.vue'
|
||||||
import Codemirror from 'codemirror-editor-vue3'
|
import CodeEditor from '@/components/Controls/CodeEditor.vue'
|
||||||
import 'codemirror/theme/seti.css'
|
|
||||||
import 'codemirror/mode/htmlmixed/htmlmixed.js'
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
fields: {
|
fields: {
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ const newJob = createResource({
|
|||||||
return {
|
return {
|
||||||
doc: {
|
doc: {
|
||||||
doctype: 'Job Opportunity',
|
doctype: 'Job Opportunity',
|
||||||
company_logo: job.image.file_url,
|
company_logo: job.image?.file_url,
|
||||||
...job,
|
...job,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,10 +82,13 @@ export function getFileSize(file_size) {
|
|||||||
|
|
||||||
export function showToast(title, text, icon, iconClasses = null) {
|
export function showToast(title, text, icon, iconClasses = null) {
|
||||||
if (!iconClasses) {
|
if (!iconClasses) {
|
||||||
iconClasses =
|
if (icon == 'check') {
|
||||||
icon == 'check'
|
iconClasses = 'bg-green-600 text-white rounded-md p-px'
|
||||||
? 'bg-green-600 text-white rounded-md p-px'
|
} else if (icon == 'circle-warn') {
|
||||||
: 'bg-red-600 text-white rounded-md p-px'
|
iconClasses = 'bg-yellow-600 text-white rounded-md p-px'
|
||||||
|
} else {
|
||||||
|
iconClasses = 'bg-red-600 text-white rounded-md p-px'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
createToast({
|
createToast({
|
||||||
title: title,
|
title: title,
|
||||||
|
|||||||
@@ -852,6 +852,11 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
vue-demi ">=0.14.8"
|
vue-demi ">=0.14.8"
|
||||||
|
|
||||||
|
ace-builds@^1.36.2:
|
||||||
|
version "1.36.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.36.2.tgz#9499bd59e839a335ac4850e74549ca8d849dc554"
|
||||||
|
integrity sha512-eqqfbGwx/GKjM/EnFu4QtQ+d2NNBu84MGgxoG8R5iyFpcVeQ4p9YlTL+ZzdEJqhdkASqoqOxCSNNGyB6lvMm+A==
|
||||||
|
|
||||||
ansi-regex@^5.0.1:
|
ansi-regex@^5.0.1:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
|
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
|
||||||
|
|||||||
@@ -293,7 +293,10 @@ def get_branding():
|
|||||||
image_fields = ["banner_image", "footer_logo", "favicon"]
|
image_fields = ["banner_image", "footer_logo", "favicon"]
|
||||||
|
|
||||||
for field in image_fields:
|
for field in image_fields:
|
||||||
website_settings.update({field: get_file_info(website_settings.get(field))})
|
if website_settings.get(field):
|
||||||
|
website_settings.update({field: get_file_info(website_settings.get(field))})
|
||||||
|
else:
|
||||||
|
website_settings.update({field: None})
|
||||||
|
|
||||||
return website_settings
|
return website_settings
|
||||||
|
|
||||||
@@ -322,7 +325,7 @@ def get_evaluator_details(evaluator):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if frappe.db.exists("Course Evaluator", {"evaluator": evaluator}):
|
if frappe.db.exists("Course Evaluator", {"evaluator": evaluator}):
|
||||||
doc = frappe.get_doc("Course Evaluator", evaluator, as_dict=1)
|
doc = frappe.get_doc("Course Evaluator", evaluator)
|
||||||
else:
|
else:
|
||||||
doc = frappe.new_doc("Course Evaluator")
|
doc = frappe.new_doc("Course Evaluator")
|
||||||
doc.evaluator = evaluator
|
doc.evaluator = evaluator
|
||||||
@@ -576,14 +579,17 @@ def get_members(start=0, search=""):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
filters = {"enabled": 1, "name": ["not in", ["Administrator", "Guest"]]}
|
filters = {"enabled": 1, "name": ["not in", ["Administrator", "Guest"]]}
|
||||||
|
or_filters = {}
|
||||||
|
|
||||||
if search:
|
if search:
|
||||||
filters["full_name"] = ["like", f"%{search}%"]
|
or_filters["full_name"] = ["like", f"%{search}%"]
|
||||||
|
or_filters["email"] = ["like", f"%{search}%"]
|
||||||
|
|
||||||
members = frappe.get_all(
|
members = frappe.get_all(
|
||||||
"User",
|
"User",
|
||||||
filters=filters,
|
filters=filters,
|
||||||
fields=["name", "full_name", "user_image", "username", "last_active"],
|
fields=["name", "full_name", "user_image", "username", "last_active"],
|
||||||
|
or_filters=or_filters,
|
||||||
page_length=20,
|
page_length=20,
|
||||||
start=start,
|
start=start,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user