fix: cache controllers and use Promise.all for concurrent execution

This commit is contained in:
Shariq Ansari 2025-05-09 15:22:40 +05:30
parent 07b2d9f792
commit 556386e446
2 changed files with 51 additions and 56 deletions

View File

@ -3,6 +3,7 @@ import { createToast } from '@/utils'
import { createDocumentResource } from 'frappe-ui'
const documentsCache = {}
const controllersCache = {}
export function useDocument(doctype, docname) {
const { setupScript } = getScript(doctype)
@ -35,63 +36,59 @@ export function useDocument(doctype, docname) {
}
function setupFormScript() {
if (documentsCache[doctype][docname]['controllers']) return
if (controllersCache[doctype]) return
const controllers = setupScript(documentsCache[doctype][docname])
if (!controllers) return
documentsCache[doctype][docname]['controllers'] = controllers
controllersCache[doctype] = setupScript(documentsCache[doctype][docname])
}
function getControllers(row = null, dt = null) {
let controllers = documentsCache[doctype][docname]?.controllers || {}
if (Object.keys(controllers).length === 0) return
dt = dt || doctype
if (!controllers[dt].length) return []
const _dt = row?.doctype ? row.doctype : doctype
const _controllers = controllers[dt].filter(
(c) => c.constructor.name === _dt.replace(/\s+/g, ''),
function getControllers(row = null) {
const _doctype = row?.doctype || doctype
return (controllersCache[doctype] || []).filter(
(c) => c.constructor.name === _doctype.replace(/\s+/g, ''),
)
return _controllers || []
}
async function triggerOnRefresh() {
const controllers = getControllers()
if (!controllers.length) return
for (const c of controllers) {
await c.refresh()
}
await Promise.all(
controllers.map(async (c) => {
await c.refresh()
}),
)
}
async function triggerOnChange(fieldname, row) {
const controllers = getControllers(row)
if (!controllers.length) return
for (const c of controllers) {
if (row) {
c.currentRowIdx = row.idx
c.value = row[fieldname]
c.oldValue = getOldValue(fieldname, row)
} else {
c.value = documentsCache[doctype][docname].doc[fieldname]
c.oldValue = getOldValue(fieldname)
}
await c[fieldname]?.()
}
await Promise.all(
controllers.map(async (c) => {
if (row) {
c.currentRowIdx = row.idx
c.value = row[fieldname]
c.oldValue = getOldValue(fieldname, row)
} else {
c.value = documentsCache[doctype][docname].doc[fieldname]
c.oldValue = getOldValue(fieldname)
}
await c[fieldname]?.()
}),
)
}
async function triggerOnRowAdd(row) {
const controllers = getControllers(row)
if (!controllers.length) return
for (const c of controllers) {
c.currentRowIdx = row.idx
c.value = row
await c[row.parentfield + '_add']?.()
}
await Promise.all(
controllers.map(async (c) => {
c.currentRowIdx = row.idx
c.value = row
await c[row.parentfield + '_add']?.()
}),
)
}
async function triggerOnRowRemove(selectedRows, rows) {
@ -99,19 +96,21 @@ export function useDocument(doctype, docname) {
const controllers = getControllers(rows[0])
if (!controllers.length) return
for (const c of controllers) {
if (selectedRows.size === 1) {
const selectedRow = Array.from(selectedRows)[0]
c.currentRowIdx = rows.find((r) => r.name === selectedRow).idx
} else {
delete c.currentRowIdx
}
await Promise.all(
controllers.map(async (c) => {
if (selectedRows.size === 1) {
const selectedRow = Array.from(selectedRows)[0]
c.currentRowIdx = rows.find((r) => r.name === selectedRow).idx
} else {
delete c.currentRowIdx
}
c.selectedRows = Array.from(selectedRows)
c.rows = rows
c.selectedRows = Array.from(selectedRows)
c.rows = rows
await c[rows[0].parentfield + '_remove']?.()
}
await c[rows[0].parentfield + '_remove']?.()
}),
)
}
function getOldValue(fieldname, row) {

View File

@ -47,7 +47,7 @@ export function getScript(doctype, view = 'Form') {
}
function setupMultipleFormControllers(scriptStrings, document, helpers) {
const controllers = {}
const controllers = []
let parentInstanceIdx = null
for (let scriptName in scriptStrings) {
@ -66,23 +66,19 @@ export function getScript(doctype, view = 'Form') {
let { doctypeMeta } = getMeta(doctype)
if (!controllers[doctype]) {
controllers[doctype] = []
}
// if className is not doctype name, then it is a child doctype
let isChildDoctype = className !== doctypeName
if (isChildDoctype) {
if (!controllers[doctype].length) {
if (!controllers.length) {
console.error(
`⚠️ No class found for doctype: ${doctype}, it is mandatory to have a class for the parent doctype. it can be empty, but it should be present.`,
)
return
}
parentInstance = controllers[doctype][parentInstanceIdx]
parentInstance = controllers[parentInstanceIdx]
} else {
parentInstanceIdx = controllers[doctype].length || 0
parentInstanceIdx = controllers.length || 0
}
const instance = setupFormController(
@ -93,7 +89,7 @@ export function getScript(doctype, view = 'Form') {
isChildDoctype,
)
controllers[doctype].push(instance)
controllers.push(instance)
})
} catch (err) {
console.error('Failed to load form controller:', err)