fix: load script and setup class instances

(cherry picked from commit 7b34c5eb66509851e993df19335a5ebedd0f3055)
This commit is contained in:
Shariq Ansari 2025-05-01 17:52:11 +05:30 committed by Mergify
parent 1a1f0478f0
commit ddc142b0bc
2 changed files with 110 additions and 17 deletions

View File

@ -1,17 +0,0 @@
import frappe
from pypika import Criterion
@frappe.whitelist()
def get_scripts(doctype, view="Form"):
Script = frappe.qb.DocType("CRM Form Script")
query = (
frappe.qb.from_(Script)
.select("*")
.where(Script.dt == doctype)
.where(Script.view == view)
.where(Script.enabled == 1)
)
scripts = query.run(as_dict=True)
return scripts

110
frontend/src/data/script.js Normal file
View File

@ -0,0 +1,110 @@
import { globalStore } from '@/stores/global'
import { createToast } from '@/utils'
import { call, createListResource } from 'frappe-ui'
import { reactive } from 'vue'
import router from '@/router'
const doctypeScripts = reactive({})
export function getScript(doctype, view = 'Form') {
const scripts = createListResource({
doctype: 'CRM Form Script',
cache: ['Form Scripts', doctype, view],
fields: ['name', 'dt', 'view', 'script'],
filters: { view, dt: doctype, enabled: 1 },
onSuccess: (_scripts) => {
for (let script of _scripts) {
if (!doctypeScripts[doctype]) {
doctypeScripts[doctype] = {}
}
doctypeScripts[doctype][script.name] = script || {}
}
},
})
if (!doctypeScripts[doctype] && !scripts.loading) {
scripts.fetch()
}
function setupScript(document, helpers = {}) {
let scripts = doctypeScripts[doctype]
if (!scripts) return null
const { $dialog, $socket, makeCall } = globalStore()
helpers.createDialog = $dialog
helpers.createToast = createToast
helpers.socket = $socket
helpers.router = router
helpers.call = call
helpers.crm = {
makePhoneCall: makeCall,
}
return setupMultipleFormControllers(scripts, document, helpers)
}
function setupMultipleFormControllers(scriptStrings, document, helpers) {
const controllers = {}
for (let scriptName in scriptStrings) {
let script = scriptStrings[scriptName]?.script
if (!script) continue
try {
const className = getClassName(script)
if (!className) throw new Error('No class found')
const FormClass = evaluateFormClass(script, className, helpers)
controllers[className] = setupFormController(FormClass, document)
} catch (err) {
console.error('Failed to load form controller:', err)
}
}
return controllers
}
function setupFormController(FormClass, document) {
const controller = new FormClass()
for (const key in document) {
if (document.hasOwnProperty(key)) {
controller[key] = document[key]
}
}
controller.actions = (controller.actions || []).filter(
(action) => typeof action.condition !== 'function' || action.condition(),
)
return controller
}
// utility function to setup a form controller
function getClassName(script) {
const match = script.match(/class\s+([A-Za-z0-9_]+)/)
return match ? match[1] : null
}
function evaluateFormClass(script, className, helpers = {}) {
const helperKeys = Object.keys(helpers)
const helperValues = Object.values(helpers)
const wrappedScript = `
${script}
return ${className};
`
const FormClass = new Function(...helperKeys, wrappedScript)(
...helperValues,
)
return FormClass
}
return {
scripts,
setupScript,
setupFormController,
}
}