From 556386e446e39d657e0bde7882924c30644b7ca8 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Fri, 9 May 2025 15:22:40 +0530 Subject: [PATCH] fix: cache controllers and use Promise.all for concurrent execution --- frontend/src/data/document.js | 93 +++++++++++++++++------------------ frontend/src/data/script.js | 14 ++---- 2 files changed, 51 insertions(+), 56 deletions(-) diff --git a/frontend/src/data/document.js b/frontend/src/data/document.js index adf49346..1d21774a 100644 --- a/frontend/src/data/document.js +++ b/frontend/src/data/document.js @@ -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) { diff --git a/frontend/src/data/script.js b/frontend/src/data/script.js index aec0d99c..03bb7818 100644 --- a/frontend/src/data/script.js +++ b/frontend/src/data/script.js @@ -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)