mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
Optimize reference update tracking by sourcing from direct modifications rather than state diff comparisons.
This commit is contained in:
parent
1c4c272c9f
commit
d4e9f45ae2
6 changed files with 95 additions and 39 deletions
|
|
@ -243,10 +243,10 @@ export const resolveReferences = (query, validationSchema, customResolvers = {},
|
|||
if (fxActive && (value.startsWith('#') || value.includes('table-'))) {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
|
||||
const { toResolveReference, jsExpression, jsExpMatch } = inferJSExpAndReferences(value, lookupTable.hints);
|
||||
const isComponentValue = toResolveReference?.startsWith('components.') || false; //!Notes: As we removed the updating of references on currentState changes, exposed variable of components are dynamic and cannot be controlled in any form, so we are resolving only components references with our legacy approach.
|
||||
if (!isComponentValue && !jsExpMatch && toResolveReference && lookupTable.hints.has(toResolveReference)) {
|
||||
|
||||
// const isComponentValue = toResolveReference?.startsWith('components.') || false; //!Notes: As we removed the updating of references on currentState changes, exposed variable of components are dynamic and cannot be controlled in any form, so we are resolving only components references with our legacy approach.
|
||||
if (!jsExpMatch && toResolveReference && lookupTable.hints.has(toResolveReference)) {
|
||||
const idToLookUp = lookupTable.hints.get(toResolveReference);
|
||||
resolvedValue = lookupTable.resolvedRefs.get(idToLookUp);
|
||||
|
||||
|
|
|
|||
|
|
@ -326,47 +326,19 @@ const EditorComponent = (props) => {
|
|||
flushComponentsToRender(updatedComponentIds);
|
||||
}
|
||||
|
||||
const lastUpdatedRef = useResolveStore((state) => state.lastUpdatedRefs, shallow);
|
||||
|
||||
useEffect(() => {
|
||||
const isEditorReady = useCurrentStateStore.getState().isEditorReady;
|
||||
|
||||
if (!isEditorReady || !onAppLoadAndPageLoadEventsAreTriggered.current) return;
|
||||
|
||||
const diffState = diff(prevCurrentStateRef.current, currentState);
|
||||
|
||||
if (Object.keys(diffState).length > 0) {
|
||||
const entitiesToTrack = ['queries', 'components', 'variables', 'page', 'constants'];
|
||||
|
||||
const entitiesChanged = Object.keys(diffState).filter((entity) => entitiesToTrack.includes(entity));
|
||||
|
||||
if (entitiesChanged.length === 0) return;
|
||||
|
||||
const diffObj = entitiesChanged.reduce((acc, entity) => {
|
||||
acc[entity] = diffState[entity];
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const allPaths = entitiesChanged.reduce((acc, entity) => {
|
||||
const paths = Object.keys(diffObj[entity]).map((key) => {
|
||||
return generatePath(diffObj[entity], key);
|
||||
});
|
||||
|
||||
acc[entity] = paths.map((path) => `${entity}.${path}`);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const currentStatePaths = Object.values(allPaths).flat();
|
||||
|
||||
if (lastUpdatedRef.length > 0) {
|
||||
const currentComponents = useEditorStore.getState().appDefinition?.pages?.[currentPageId]?.components || {};
|
||||
const componentIdsWithReferences = findComponentsWithReferences(currentComponents, currentStatePaths);
|
||||
const componentIdsWithReferences = findComponentsWithReferences(currentComponents, lastUpdatedRef);
|
||||
|
||||
if (componentIdsWithReferences.length > 0) {
|
||||
batchUpdateComponents(componentIdsWithReferences);
|
||||
}
|
||||
|
||||
prevCurrentStateRef.current = JSON.parse(JSON.stringify(currentState));
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [JSON.stringify(currentState)]);
|
||||
}, [lastUpdatedRef]);
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
|
|
@ -1175,7 +1147,6 @@ const EditorComponent = (props) => {
|
|||
});
|
||||
|
||||
useResolveStore.getState().actions.addEntitiesToMap(componentEntityArray);
|
||||
|
||||
useResolveStore.getState().actions.addAppSuggestions({
|
||||
components: newComponentsExposedData,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import { useAppDataStore } from '@/_stores/appDataStore';
|
|||
import { useEditorStore } from '@/_stores/editorStore';
|
||||
import { useGridStore } from '@/_stores/gridStore';
|
||||
import { useResolveStore } from '@/_stores/resolverStore';
|
||||
import { handleLowPriorityWork } from './editorHelpers';
|
||||
|
||||
const ERROR_TYPES = Object.freeze({
|
||||
ReferenceError: 'ReferenceError',
|
||||
|
|
@ -115,11 +116,31 @@ export function onComponentOptionChanged(component, option_name, value) {
|
|||
let componentData = components[componentName] || {};
|
||||
componentData[option_name] = value;
|
||||
|
||||
const path = option_name ? `components.${componentName}.${option_name}` : null;
|
||||
|
||||
if (isEditorReady) {
|
||||
// Always update the current state if editor is ready
|
||||
useCurrentStateStore.getState().actions.setCurrentState({
|
||||
components: { ...components, [componentName]: componentData },
|
||||
});
|
||||
|
||||
if (!_.isEmpty(useResolveStore.getState().lookupTable?.resolvedRefs) && path) {
|
||||
const lookUpTable = useResolveStore.getState().lookupTable;
|
||||
|
||||
const existingRef = lookUpTable.resolvedRefs?.get(lookUpTable.hints?.get(path));
|
||||
|
||||
if (typeof existingRef === 'function') return;
|
||||
|
||||
const shouldUpdateRef = existingRef !== componentData[option_name];
|
||||
|
||||
if (shouldUpdateRef) {
|
||||
handleLowPriorityWork(() => {
|
||||
useResolveStore
|
||||
.getState()
|
||||
.actions.updateResolvedRefsOfHints([{ hint: path, newRef: componentData[option_name] }]);
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Update the duplicate state if editor is not ready
|
||||
duplicateCurrentState = { ...components, [componentName]: componentData };
|
||||
|
|
@ -1091,6 +1112,14 @@ export function runQuery(
|
|||
},
|
||||
errors: {},
|
||||
});
|
||||
useResolveStore.getState().actions.addAppSuggestions({
|
||||
queries: {
|
||||
[queryName]: {
|
||||
data: [],
|
||||
isLoading: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
let queryExecutionPromise = null;
|
||||
if (query.kind === 'runjs') {
|
||||
|
|
@ -1267,9 +1296,15 @@ export function runQuery(
|
|||
queries: {
|
||||
[queryName]: {
|
||||
data: finalData,
|
||||
isLoading: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const basePath = `queries.${queryName}`;
|
||||
|
||||
useResolveStore.getState().actions.updateLastUpdatedRefs([`${basePath}.data`, `${basePath}.isLoading`]);
|
||||
|
||||
resolve({ status: 'ok', data: finalData });
|
||||
onEvent(_self, 'onDataQuerySuccess', queryEvents, mode);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import _ from 'lodash';
|
||||
import { create } from './utils';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { useResolveStore } from './resolverStore';
|
||||
const STORE_NAME = 'Editor';
|
||||
|
||||
export const EMPTY_ARRAY = [];
|
||||
|
|
@ -117,4 +118,5 @@ export const flushComponentsToRender = (componentIds = []) => {
|
|||
if (!componentIds.length) return;
|
||||
|
||||
useEditorStore.getState().actions.flushComponentsNeedsUpdateOnNextRender(componentIds);
|
||||
useResolveStore.getState().actions.getLastUpdatedRefs();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ const initialState = {
|
|||
hints: {},
|
||||
resolvedRefs: {},
|
||||
},
|
||||
|
||||
lastUpdatedRefs: [],
|
||||
referenceMapper: new ReferencesBiMap(),
|
||||
};
|
||||
|
||||
|
|
@ -78,6 +78,16 @@ export const useResolveStore = create(
|
|||
}));
|
||||
},
|
||||
|
||||
flushLastUpdatedRefs: () => {
|
||||
set(() => ({ lastUpdatedRefs: [] }));
|
||||
},
|
||||
getLastUpdatedRefs: () => {
|
||||
return get().lastUpdatedRefs;
|
||||
},
|
||||
//for queries references used in component definitons
|
||||
updateLastUpdatedRefs: (updatedRefs) => {
|
||||
set(() => ({ lastUpdatedRefs: updatedRefs }));
|
||||
},
|
||||
addAppSuggestions: (partialRefState) => {
|
||||
if (Object.keys(partialRefState).length === 0) return;
|
||||
|
||||
|
|
@ -86,6 +96,8 @@ export const useResolveStore = create(
|
|||
const lookupHintsMap = new Map([...get().lookupTable.hints]);
|
||||
const lookupResolvedRefs = new Map([...get().lookupTable.resolvedRefs]);
|
||||
|
||||
const newUpdatedrefs = [];
|
||||
|
||||
hintsMap.forEach((value, key) => {
|
||||
const alreadyExists = lookupHintsMap.has(key);
|
||||
|
||||
|
|
@ -97,6 +109,7 @@ export const useResolveStore = create(
|
|||
|
||||
resolvedRefs.delete(value);
|
||||
resolvedRefs.set(existingLookupId, newResolvedRef);
|
||||
newUpdatedrefs.push(key);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -118,6 +131,7 @@ export const useResolveStore = create(
|
|||
hints: lookupHintsMap,
|
||||
resolvedRefs: lookupResolvedRefs,
|
||||
},
|
||||
lastUpdatedRefs: newUpdatedrefs,
|
||||
}));
|
||||
},
|
||||
|
||||
|
|
@ -158,6 +172,35 @@ export const useResolveStore = create(
|
|||
});
|
||||
},
|
||||
|
||||
updateResolvedRefsOfHints: (resolvedRefs = []) => {
|
||||
const lookupResolvedRefs = new Map([...get().lookupTable.resolvedRefs]);
|
||||
const hintsMap = new Map([...get().lookupTable.hints]);
|
||||
|
||||
const updatedList = [];
|
||||
|
||||
resolvedRefs.forEach((ref) => {
|
||||
if (!ref.hint || !ref.newRef || !hintsMap.has(ref.hint)) return;
|
||||
|
||||
const refId = hintsMap.get(ref.hint);
|
||||
const currentRef = lookupResolvedRefs.get(refId);
|
||||
|
||||
if (currentRef !== ref.newRef) {
|
||||
lookupResolvedRefs.set(refId, ref.newRef);
|
||||
updatedList.push(ref.hint);
|
||||
}
|
||||
});
|
||||
|
||||
if (updatedList.length > 0) {
|
||||
set(() => ({
|
||||
lookupTable: {
|
||||
...get().lookupTable,
|
||||
resolvedRefs: lookupResolvedRefs,
|
||||
},
|
||||
lastUpdatedRefs: updatedList,
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
updateJSHints: () => {
|
||||
const hints = createJavaScriptSuggestions();
|
||||
set(() => ({ suggestions: { ...get().suggestions, jsHints: hints } }));
|
||||
|
|
|
|||
|
|
@ -465,7 +465,12 @@ export function createReferencesLookup(refState, forQueryParams = false, initalL
|
|||
}
|
||||
if (_type === 'Array') {
|
||||
map.set(newPath, { type: _type });
|
||||
buildMap(value, newPath);
|
||||
|
||||
if (path.startsWith('queries') && key === 'data' && value.length > 2) {
|
||||
// do nothing
|
||||
} else {
|
||||
buildMap(value, newPath);
|
||||
}
|
||||
} else {
|
||||
map.set(newPath, { type: _type });
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue