Merge branch 'core-performance/appbuilder' into builder-performance-platform-part/release

This commit is contained in:
Muhsin Shah 2024-04-05 13:26:23 +05:30
commit b5c6a16cd8
28 changed files with 327 additions and 498 deletions

View file

@ -147,7 +147,6 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
"@welldone-software/why-did-you-render": "^8.0.1",
"babel-loader": "^9.1.2",
"babel-plugin-console-source": "^2.0.5",
"babel-plugin-import": "^1.13.6",
@ -12288,18 +12287,6 @@
}
}
},
"node_modules/@welldone-software/why-did-you-render": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/@welldone-software/why-did-you-render/-/why-did-you-render-8.0.1.tgz",
"integrity": "sha512-PtLBjiHNX04gDPheMeAQP16S24JV3SOW6wGDUrm4bFPZmofmmflgvd4Kacf/jhB8zlX6equ8m3t6CS+OxA3Q4g==",
"dev": true,
"dependencies": {
"lodash": "^4"
},
"peerDependencies": {
"react": "^18"
}
},
"node_modules/@xtuc/ieee754": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",

View file

@ -142,7 +142,6 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
"@welldone-software/why-did-you-render": "^8.0.1",
"babel-loader": "^9.1.2",
"babel-plugin-console-source": "^2.0.5",
"babel-plugin-import": "^1.13.6",

View file

@ -2,6 +2,8 @@ import React from 'react';
import HydrateWithResolveReferences from './Middlewares/HydrateWithResolveReferences';
import BoxUI from './BoxUI';
import _ from 'lodash';
import { useEditorStore } from '@/_stores/editorStore';
import { shallow } from 'zustand/shallow';
function deepEqualityCheckusingLoDash(obj1, obj2) {
return _.isEqual(obj1, obj2);
@ -19,6 +21,12 @@ export const shouldUpdate = (prevProps, nextProps) => {
export const Box = (props) => {
const { id, component, mode, customResolvables } = props;
/**
* !This component does not consume the value returned from the below hook.
* Only purpose of the hook is to force one rerender the component
* */
useEditorStore((state) => state.componentsNeedsUpdateOnNextRender.find((compId) => compId === id), shallow);
return (
<HydrateWithResolveReferences id={id} mode={mode} component={component} customResolvables={customResolvables}>
<BoxUI {...props} />

View file

@ -32,12 +32,11 @@ const BoxUI = (props) => {
changeCanDrag,
removeComponent,
canvasWidth,
// exposedVariables,
// fireEvent,
parentId,
customResolvables,
currentLayout,
readOnly,
currentPageId,
} = props;
const darkMode = localStorage.getItem('darkMode') === 'true';
@ -120,10 +119,9 @@ const BoxUI = (props) => {
<div
style={{
..._styles,
// backgroundColor,
padding: _styles?.padding == 'none' ? '0px' : '2px', //chart and image has a padding property other than container padding
}}
// role={preview ? 'BoxPreview' : 'Box'}
role={'Box'}
>
<ControlledComponentToRender
@ -166,6 +164,8 @@ const BoxUI = (props) => {
dataCy={`draggable-widget-${String(component.name).toLowerCase()}`}
currentLayout={currentLayout}
currentState={currentState}
currentPageId={currentPageId}
getContainerProps={component.component === 'Form' ? getContainerProps : null}
/>
</div>
</OverlayTrigger>

View file

@ -95,7 +95,6 @@ export function CodeBuilder({ initialValue, onChange, components }) {
return { item: item };
});
} else {
console.log(currentWord);
filteredVariables = fuse.search(currentWord);
}
return filteredVariables.map((variable) => renderVariable(type, key, variable.item.name));

View file

@ -243,10 +243,9 @@ 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)) {
if (!jsExpMatch && toResolveReference && lookupTable.hints.has(toResolveReference)) {
const idToLookUp = lookupTable.hints.get(toResolveReference);
resolvedValue = lookupTable.resolvedRefs.get(idToLookUp);

View file

@ -24,17 +24,19 @@ export const Form = function Form(props) {
fireEvent,
properties,
resetComponent,
childComponents,
onEvent,
dataCy,
paramUpdated,
currentLayout,
mode,
getContainerProps,
containerProps,
} = props;
const { events: allAppEvents } = useAppInfo();
const { childComponents } = containerProps;
const formEvents = allAppEvents.filter((event) => event.target === 'component' && event.sourceId === id);
const { visibility, disabledState, borderRadius, borderColor, boxShadow } = styles;
const { buttonToSubmit, loadingState, advanced, JSONSchema } = properties;
@ -135,7 +137,7 @@ export const Form = function Form(props) {
formattedChildData = extractData(childrenData);
childValidation = checkJsonChildrenValidtion();
} else {
Object.keys(childComponents).forEach((childId) => {
Object.keys(childComponents ?? {}).forEach((childId) => {
if (childrenData[childId]?.name) {
formattedChildData[childrenData[childId].name] = { ...omit(childrenData[childId], 'name'), id: childId };
childValidation = childValidation && (childrenData[childId]?.isValid ?? true);
@ -252,6 +254,8 @@ export const Form = function Form(props) {
onOptionChange({ component, optionName, value, componentId });
}
}}
currentPageId={props.currentPageId}
{...props}
/>
<SubCustomDragLayer
containerCanvasWidth={width}
@ -276,6 +280,7 @@ export const Form = function Form(props) {
key={index}
>
<Box
{...props}
component={item}
id={id}
width={width}
@ -292,7 +297,6 @@ export const Form = function Form(props) {
// customResolvables={customResolvables}
parentId={id}
getContainerProps={getContainerProps}
{...props}
/>
</div>
);

View file

@ -128,9 +128,7 @@ export const Container = ({
: updatedBoxes[id].layouts.desktop;
});
setBoxes({ ...updatedBoxes });
// console.log('currentLayout', data);
}
// setNoOfGrids(currentLayout === 'mobile' ? 12 : 43);
}, [currentLayout]);
const paramUpdatesOptsRef = useRef({});
@ -316,10 +314,6 @@ export const Container = ({
[setCanvasHeight, currentLayout, mode]
);
// useEffect(() => {
// setIsDragging(draggingState);
// }, [draggingState]);
const [{ isOver, isOverCurrent }, drop] = useDrop(
() => ({
accept: ItemTypes.BOX,
@ -372,6 +366,86 @@ export const Container = ({
zoomLevel
);
// Logic to add default child components
const childrenBoxes = {};
if (componentMeta.defaultChildren) {
const parentMeta = componentMeta;
const widgetResolvables = Object.freeze({
Listview: 'listItem',
});
const customResolverVariable = widgetResolvables[parentMeta?.component];
const defaultChildren = _.cloneDeep(parentMeta)['defaultChildren'];
const parentId = newComponent.id;
defaultChildren.forEach((child) => {
const { componentName, layout, incrementWidth, properties, accessorKey, tab, defaultValue, styles } = child;
const componentMeta = _.cloneDeep(
componentTypes.find((component) => component.component === componentName)
);
const componentData = JSON.parse(JSON.stringify(componentMeta));
const width = layout.width ? layout.width : (componentMeta.defaultSize.width * 100) / noOfGrids;
const height = layout.height ? layout.height : componentMeta.defaultSize.height;
const newComponentDefinition = {
...componentData.definition.properties,
};
if (_.isArray(properties) && properties.length > 0) {
properties.forEach((prop) => {
const accessor = customResolverVariable
? `{{${customResolverVariable}.${accessorKey}}}`
: defaultValue[prop] || '';
_.set(newComponentDefinition, prop, {
value: accessor,
});
});
_.set(componentData, 'definition.properties', newComponentDefinition);
}
if (_.isArray(styles) && styles.length > 0) {
styles.forEach((prop) => {
const accessor = customResolverVariable
? `{{${customResolverVariable}.${accessorKey}}}`
: defaultValue[prop] || '';
_.set(newComponentDefinition, prop, {
value: accessor,
});
});
_.set(componentData, 'definition.styles', newComponentDefinition);
}
const newChildComponent = addNewWidgetToTheEditor(
componentData,
{},
boxes,
{},
item.currentLayout,
snapToGrid,
zoomLevel,
true,
true
);
_.set(childrenBoxes, newChildComponent.id, {
component: {
...newChildComponent.component,
parent: parentMeta.component === 'Tabs' ? parentId + '-' + tab : parentId,
},
layouts: {
[currentLayout]: {
...layout,
width: incrementWidth ? width * incrementWidth : width,
height: height,
},
},
});
});
}
const newBoxes = {
...boxes,
[newComponent.id]: {
@ -379,8 +453,8 @@ export const Container = ({
layouts: {
...newComponent.layout,
},
withDefaultChildren: newComponent.withDefaultChildren,
},
...childrenBoxes,
};
setBoxes(newBoxes);
@ -445,8 +519,6 @@ export const Container = ({
setBoxes(updatedBoxes);
updateCanvasHeight(updatedBoxes);
};
// [boxes, updateCanvasHeight, canvasWidth, gridWidth, currentLayout]
// );
function onDragStop(boxPositions) {
const copyOfBoxes = JSON.parse(JSON.stringify(boxes));
@ -679,8 +751,6 @@ export const Container = ({
}, [components]);
const getContainerProps = React.useCallback((componentId) => {
const withDefaultChildren = boxes[componentId]?.withDefaultChildren;
return {
mode,
snapToGrid,
@ -696,7 +766,6 @@ export const Container = ({
currentLayout,
selectedComponents,
darkMode,
addDefaultChildren: withDefaultChildren,
currentPageId,
childComponents: childComponents[componentId],
parentGridWidth: gridWidth,
@ -785,6 +854,7 @@ export const Container = ({
isMultipleComponentsSelected={selectedComponents?.length > 1 ? true : false}
getContainerProps={getContainerProps}
isVersionReleased={isVersionReleased}
currentPageId={currentPageId}
/>
</WidgetWrapper>
);
@ -803,10 +873,7 @@ export const Container = ({
onDrag={onDragStop}
gridWidth={gridWidth}
selectedComponents={selectedComponents}
// setIsDragging={setIsDragging}
// setIsResizing={setIsResizing}
currentLayout={currentLayout}
// subContainerWidths={subContainerWidths}
currentPageId={currentPageId}
draggedSubContainer={draggedSubContainer}
mode={isVersionReleased ? 'view' : mode}
@ -862,7 +929,6 @@ const WidgetWrapper = ({ children, widget, id, gridWidth, currentLayout, isResiz
width: width + 'px',
height: layoutData.height + 'px',
transform: `translate(${layoutData.left * gridWidth}px, ${layoutData.top}px)`,
// ...(isGhostComponent ? { opacity: 0.5 } : isResizing ? { opacity: 0 } : {}),
...(isGhostComponent ? { opacity: 0.5 } : {}),
...(isWidgetActive ? { zIndex: 3 } : {}),
};
@ -907,18 +973,7 @@ function DragGhostWidget() {
);
}
function ContainerWrapper({
children,
canvasHeight,
// isDragging,
// isResizing,
isDropping,
showComments,
handleAddThread,
containerRef,
styles,
}) {
// const [dragTarget] = useDragTarget();
function ContainerWrapper({ children, canvasHeight, isDropping, showComments, handleAddThread, containerRef, styles }) {
const { resizingComponentId, draggingComponentId, dragTarget } = useGridStore((state) => {
const { resizingComponentId, draggingComponentId, dragTarget } = state;
return { resizingComponentId, draggingComponentId, dragTarget };
@ -930,7 +985,6 @@ function ContainerWrapper({
ref={containerRef}
style={{ ...styles, height: canvasHeight }}
className={cx('real-canvas', {
// 'show-grid': isDragging || isResizing || dragTarget === 'canvas',
'show-grid': (!!resizingComponentId && !dragTarget) || (!!draggingComponentId && !dragTarget) || isDropping,
})}
id="real-canvas"

View file

@ -1,8 +1,8 @@
import React, { useEffect, useState } from 'react';
import React from 'react';
import { getComponentToRender } from '@/_helpers/editorHelpers';
import _ from 'lodash';
import { flushComponentsToRender, getComponentsToRenders } from '@/_stores/editorStore';
import { getComponentsToRenders } from '@/_stores/editorStore';
function deepEqualityCheckusingLoDash(obj1, obj2) {
return _.isEqual(obj1, obj2);
@ -17,6 +17,7 @@ export const shouldUpdate = (prevProps, nextProps) => {
if (componentId) {
const componentToRender = listToRender.find((item) => item === componentId);
if (componentToRender) {
needToRender = true;
}
@ -34,15 +35,6 @@ export const shouldUpdate = (prevProps, nextProps) => {
const ComponentWrapper = React.memo(({ componentName, ...props }) => {
const ComponentToRender = getComponentToRender(componentName);
const [shouldFlush, setShouldFlush] = useState(false);
useEffect(() => {
if (shouldFlush) {
flushComponentsToRender();
setShouldFlush(false); // Reset the condition
}
}, [shouldFlush]);
return <ComponentToRender {...props} />;
}, shouldUpdate);

View file

@ -24,10 +24,7 @@ export default function DragContainer({
onDrag,
gridWidth,
selectedComponents = [],
// setIsDragging,
// setIsResizing,
currentLayout,
// subContainerWidths,
draggedSubContainer,
}) {
const lastDraggedEventsRef = useRef(null);
@ -112,8 +109,6 @@ export default function DragContainer({
},
};
// const [dragTarget, useGridStore.getState().actions.setDragTarget] = useDragTarget();
// const [draggedTarget, setDraggedTarget] = useState();
const moveableRef = useRef();
const draggedOverElemRef = useRef(null);
const childMoveableRefs = useRef({});
@ -171,7 +166,6 @@ export default function DragContainer({
console.error('Error---->', error);
}
}, [hoveredComponent, reloadGrid]);
// }, [JSON.stringify(selectedComponents), JSON.stringify(boxes), hoveredComponent]);
useEffect(() => {
setList(boxList);
@ -233,16 +227,12 @@ export default function DragContainer({
}
}, [selectedComponents]);
// window.reloadGrid = reloadGrid;
useEffect(() => {
setList(boxList);
}, [JSON.stringify(boxes)]);
const groupedTargets = [
...findHighestLevelofSelection(selectedComponents)
// .filter((component) => !component?.component?.parent)
.map((component) => '.ele-' + component.id),
...findHighestLevelofSelection(selectedComponents).map((component) => '.ele-' + component.id),
];
useEffect(() => {
@ -257,8 +247,6 @@ export default function DragContainer({
lastDraggedEventsRef.current = posWithParent;
};
// const handleResize = useCallback((e) => handleWidgetResize(e, list, boxes, gridWidth), [list, boxes, gridWidth]);
return mode === 'edit' ? (
<>
<Moveable
@ -386,12 +374,7 @@ export default function DragContainer({
onResizeStart={(e) => {
performance.mark('onResizeStart');
useGridStore.getState().actions.setResizingComponentId(e.target.id);
// setIsResizing(true);
e.setMin([gridWidth, 10]);
// if (currentLayout === 'mobile' && autoComputeLayout) {
// turnOffAutoLayout();
// return false;
// }
}}
onResizeGroupStart={({ events }) => {
const parentElm = events[0].target.closest('.real-canvas');
@ -500,15 +483,12 @@ export default function DragContainer({
if (hoveredComponent !== e.target.id) {
return false;
}
// setDraggedTarget(e.target.id);
}}
onDragEnd={(e) => {
try {
if (isDraggingRef.current) {
// setTimeout(() => useGridStore.getState().actions.setDraggingComponentId(null));
useGridStore.getState().actions.setDraggingComponentId(null);
isDraggingRef.current = false;
// setIsDragging(false);
}
if (draggedSubContainer) {
@ -612,20 +592,16 @@ export default function DragContainer({
element.classList.remove('show-grid');
element.classList.add('hide-grid');
});
// setDraggedTarget();
}}
onDrag={(e) => {
if (!isDraggingRef.current) {
useGridStore.getState().actions.setDraggingComponentId(e.target.id);
isDraggingRef.current = true;
// setIsDragging(true);
}
if (draggedSubContainer) {
return;
}
// if (e.target.id !== draggedTarget) {
// setDraggedTarget(e.target.id);
// }
if (!draggedSubContainer) {
const parentComponent = widgets[widgets[e.target.id]?.component?.parent];
let top = e.translate[1];
@ -667,7 +643,7 @@ export default function DragContainer({
});
const parentWidgetId = draggedOverContainer.getAttribute('data-parent') || draggedOverElem?.id;
document.getElementById('canvas-' + parentWidgetId)?.classList.add('show-grid');
console.log('dragTarget-- parentWidgetId', parentWidgetId);
useGridStore.getState().actions.setDragTarget(parentWidgetId);
if (
@ -679,7 +655,7 @@ export default function DragContainer({
draggedOverElemRef.current = draggedOverContainer;
}
}
console.log('getOffset--', getOffset(e.target, document.querySelector('#real-canvas')));
const offset = getOffset(e.target, document.querySelector('#real-canvas'));
if (document.getElementById('moveable-drag-ghost')) {
document.getElementById('moveable-drag-ghost').style.transform = `translate(${offset.x}px, ${offset.y}px)`;
@ -862,8 +838,3 @@ function getOffset(childElement, grandparentElement) {
return { x: offsetX, y: offsetY };
}
DragContainer.whyDidYouRender = {
logOnDifferentValues: true,
customName: 'WDYRDragContainer',
};

View file

@ -16,8 +16,6 @@ import WidgetBox from './WidgetBox';
import * as Sentry from '@sentry/react';
import { findHighestLevelofSelection } from './DragContainer';
// const noOfGrid = 43;
function computeWidth(currentLayoutOptions) {
return `${currentLayoutOptions?.width}%`;
}
@ -54,6 +52,7 @@ const DraggableBox = React.memo(
customResolvables,
parentId,
getContainerProps,
currentPageId,
}) => {
const isResizing = useGridStore((state) => state.resizingComponentId === id);
const [canDrag, setCanDrag] = useState(true);
@ -222,6 +221,7 @@ const DraggableBox = React.memo(
customResolvables={customResolvables}
parentId={parentId}
getContainerProps={getContainerProps}
currentPageId={currentPageId}
/>
</Sentry.ErrorBoundary>
</div>
@ -238,9 +238,4 @@ const DraggableBox = React.memo(
}
);
// DraggableBox.whyDidYouRender = {
// logOnDifferentValues: true,
// customName: 'WDYRDraggableBox',
// };
export { DraggableBox };

View file

@ -70,7 +70,7 @@ import {
resetAllStores,
} from '@/_stores/utils';
import { setCookie } from '@/_helpers/cookie';
import { EMPTY_ARRAY, useEditorActions, useEditorStore } from '@/_stores/editorStore';
import { EMPTY_ARRAY, flushComponentsToRender, useEditorActions, useEditorStore } from '@/_stores/editorStore';
import { useAppDataActions, useAppDataStore } from '@/_stores/appDataStore';
import { useNoOfGrid } from '@/_stores/gridStore';
import { useMounted } from '@/_hooks/use-mount';
@ -89,7 +89,7 @@ import { HotkeysProvider } from 'react-hotkeys-hook';
import { useResolveStore } from '@/_stores/resolverStore';
import { dfs } from '@/_stores/handleReferenceTransactions';
import { decimalToHex } from './editorConstants';
import { findComponentsWithReferences, handleLowPriorityWork } from '@/_helpers/editorHelpers';
import { findComponentsWithReferences, generatePath, handleLowPriorityWork } from '@/_helpers/editorHelpers';
setAutoFreeze(false);
enablePatches();
@ -212,7 +212,8 @@ const EditorComponent = (props) => {
const selectionRef = useRef(null);
const prevAppDefinition = useRef(appDefinition);
const prevEventsStoreRef = useRef(events);
const onAppLoadAndPageLoadEventsAreTriggered = useRef(false);
useLayoutEffect(() => {
resetAllStores();
@ -287,27 +288,57 @@ const EditorComponent = (props) => {
if (appDiffOptions?.skipAutoSave === true || appDiffOptions?.entityReferenceUpdated === true) return;
if (useEditorStore.getState().isUpdatingEditorStateInProcess) {
handleLowPriorityWork(() => autoSave());
}
handleLowPriorityWork(() => autoSave());
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify({ appDefinition, currentPageId, dataQueries })]);
const currentStateDiff = useEditorStore.getState().currentStateDiff;
useEffect(() => {
const isEditorReady = useCurrentStateStore.getState().isEditorReady;
const prevCurrentStateRef = useRef(currentState);
if (isEditorReady && currentStateDiff?.length > 0) {
/**
** Async updates components in batches to optimize and processing efficiency.
* This function iterates over an array of component IDs, updating them in fixed-size batches,
* and introduces a delay after each batch to allow the UI thread to manage other tasks, such as rendering updates.
* After all batches are processed, it flushes the updates to clear any flags or temporary states indicating pending updates,
* ensuring the system is ready for the next cycle of updates.
*
* @param {Array} componentIds An array of component IDs that need updates.
* @returns {Promise<void>} A promise that resolves once all batches have been processed and flushed.
*/
async function batchUpdateComponents(componentIds) {
if (componentIds.length === 0) return;
let updatedComponentIds = [];
for (let i = 0; i < componentIds.length; i += 10) {
const batch = componentIds.slice(i, i + 10);
batch.forEach((id) => {
updatedComponentIds.push(id);
});
updateComponentsNeedsUpdateOnNextRender(batch);
// Delay to allow UI to process
await new Promise((resolve) => setTimeout(resolve, 0));
}
// Flush only updated components
flushComponentsToRender(updatedComponentIds);
}
const lastUpdatedRef = useResolveStore((state) => state.lastUpdatedRefs, shallow);
useEffect(() => {
if (lastUpdatedRef.length > 0) {
const currentComponents = useEditorStore.getState().appDefinition?.pages?.[currentPageId]?.components || {};
const componentIdsWithReferences = findComponentsWithReferences(currentComponents, currentStateDiff);
const componentIdsWithReferences = findComponentsWithReferences(currentComponents, lastUpdatedRef);
if (componentIdsWithReferences.length > 0) {
updateComponentsNeedsUpdateOnNextRender(componentIdsWithReferences);
batchUpdateComponents(componentIdsWithReferences);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(currentStateDiff)]);
}, [lastUpdatedRef]);
useEffect(
() => {
@ -345,14 +376,6 @@ const EditorComponent = (props) => {
}
}, [currentLayout, mounted]);
const handleYmapEventUpdates = () => {
props.ymap?.set('eventHandlersUpdated', {
currentVersionId: currentVersionId,
currentSessionId: currentSessionId,
update: true,
});
};
const handleMessage = (event) => {
const { data } = event;
@ -482,11 +505,6 @@ const EditorComponent = (props) => {
socket?.addEventListener('message', (event) => {
const data = event.data.replace(/^"(.+(?="$))"$/, '$1');
if (data === 'versionReleased') fetchApp();
// else if (data === 'dataQueriesChanged') {
// fetchDataQueries(editingVersion?.id);
// } else if (data === 'dataSourcesChanged') {
// fetchDataSources(editingVersion?.id);
// }
});
};
@ -606,14 +624,6 @@ const EditorComponent = (props) => {
const handleQueryPaneDragging = (bool) => setIsQueryPaneDragging(bool);
const handleQueryPaneExpanding = (bool) => setIsQueryPaneExpanded(bool);
const handleOnComponentOptionChanged = (component, optionName, value) => {
return onComponentOptionChanged(component, optionName, value);
};
const handleOnComponentOptionsChanged = (component, options) => {
return onComponentOptionsChanged(component, options);
};
const changeDarkMode = (newMode) => {
useCurrentStateStore.getState().actions.setCurrentState({
globals: {
@ -624,16 +634,9 @@ const EditorComponent = (props) => {
props.switchDarkMode(newMode);
};
// const handleEvent = memoizeFunction((eventName, event, options) => {
// return onEvent(getEditorRef(), eventName, event, options, 'edit');
// });
// const handleEvent = (eventName, event, options) => {
// return onEvent(getEditorRef(), eventName, event, options, 'edit');
// };
const handleEvent = React.useCallback((eventName, event, options) => {
return onEvent(getEditorRef(), eventName, event, options, 'edit');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleRunQuery = (queryId, queryName) => runQuery(getEditorRef(), queryId, queryName);
@ -672,7 +675,6 @@ const EditorComponent = (props) => {
};
const getPagesWithIds = () => {
//! Needs attention
return Object.entries(appDefinition?.pages).map(([id, page]) => ({ ...page, id }));
};
@ -741,13 +743,12 @@ const EditorComponent = (props) => {
useCurrentStateStore.getState().actions.setCurrentState({
page: currentpageData,
});
updateEditorState({
isLoading: false,
appDefinition: appJson,
isUpdatingEditorStateInProcess: false,
});
}),
updateEditorState({
isLoading: false,
appDefinition: appJson,
isUpdatingEditorStateInProcess: false,
});
updateState({ components: appJson.pages[homePageId]?.components });
@ -898,6 +899,7 @@ const EditorComponent = (props) => {
handleLowPriorityWork(async () => {
await runQueries(useDataQueriesStore.getState().dataQueries, editorRef, true);
await handleEvent('onPageLoad', currentPageEvents, {}, true);
await handleLowPriorityWork(() => (onAppLoadAndPageLoadEventsAreTriggered.current = true));
});
});
};

View file

@ -27,7 +27,6 @@ const EditorSelecto = ({
const onAreaSelectionStart = useCallback(
(e) => {
console.log('onAreaSelectionStart', e);
const isMultiSelect = e.inputEvent.shiftKey || useEditorStore.getState().selectedComponents.length > 0;
setSelectionInProgress(true);
setSelectedComponents([...(isMultiSelect ? useEditorStore.getState().selectedComponents : EMPTY_ARRAY)]);
@ -36,7 +35,6 @@ const EditorSelecto = ({
);
const onAreaSelection = useCallback((e) => {
console.log('onAreaSelection', e);
e.added.forEach((el) => {
el.classList.add('resizer-select');
});
@ -52,7 +50,6 @@ const EditorSelecto = ({
const onAreaSelectionEnd = useCallback(
(e) => {
console.log('onAreaSelectionEnd', e);
setSelectionInProgress(false);
e.selected.forEach((el, index) => {
const id = el.getAttribute('widgetid');

View file

@ -14,7 +14,6 @@ const useDebugger = ({ currentPageId, isDebuggerOpen }) => {
const { errors, succededQuery } = useCurrentStateStore(
(state) => ({
errors: state.errors,
queries: state.queries,
succededQuery: state.succededQuery,
}),
shallow

View file

@ -1,7 +1,7 @@
/* eslint-disable import/no-named-as-default */
import React, { useCallback, useState, useEffect, useRef, useMemo } from 'react';
import React, { useState, useEffect, useRef, useMemo } from 'react';
import { useDrop } from 'react-dnd';
import { EditorConstants, ItemTypes } from './editorConstants';
import { ItemTypes } from './editorConstants';
import { DraggableBox } from './DraggableBox';
import update from 'immutability-helper';
import _, { isEmpty } from 'lodash';
@ -21,23 +21,17 @@ import { useGridStore, useResizingComponentId } from '@/_stores/gridStore';
import { isPDFSupported } from '@/_stores/utils';
import GhostWidget from './GhostWidget';
const deviceWindowWidth = EditorConstants.deviceWindowWidth;
export const SubContainer = ({
mode,
snapToGrid,
onComponentClick,
onEvent,
// appDefinition,
appDefinitionChanged,
// onComponentOptionChanged,
// onComponentOptionsChanged,
appLoading,
zoomLevel,
parent,
parentRef,
setSelectedComponent,
// deviceWindowWidth,
selectedComponent,
currentLayout,
removeComponent,
@ -51,25 +45,21 @@ export const SubContainer = ({
sideBarDebugger,
onOptionChange,
exposedVariables,
addDefaultChildren = false,
height = '100%',
currentPageId,
childComponents = null,
listmode = null,
columns = 1,
// setSubContainerWidths,
parentWidgetId,
// turnOffAutoLayout,
}) => {
//Todo add custom resolve vars for other widgets too
const mounted = useMounted();
const widgetResolvables = Object.freeze({
Listview: 'listItem',
});
const appDefinition = useEditorStore((state) => state.appDefinition, shallow);
const customResolverVariable = widgetResolvables[parentComponent?.component];
const currentState = useCurrentState();
const { selectedComponents } = useEditorStore(
(state) => ({
@ -80,7 +70,6 @@ export const SubContainer = ({
const resizingComponentId = useResizingComponentId();
// const [noOfGrids] = useNoOfGrid();
const noOfGrids = 43;
const { isGridActive } = useGridStore((state) => ({ isGridActive: state.activeGrid === parent }), shallow);
@ -97,6 +86,7 @@ export const SubContainer = ({
zoomLevel = zoomLevel || 1;
// eslint-disable-next-line react-hooks/exhaustive-deps
const allComponents = appDefinition.pages[currentPageId]?.components ?? {};
const allChildComponents = useMemo(() => {
@ -110,11 +100,10 @@ export const SubContainer = ({
return _childWidgets;
}, [allComponents, parent]);
// const [boxes, setBoxes] = useState(allComponents);
const [childWidgets, setChildWidgets] = useState(() => allChildComponents);
const [isDragging, setIsDragging] = useState(false);
const [isResizing, setIsResizing] = useState(false);
// const [subContainerHeight, setSubContainerHeight] = useState('100%'); //used to determine the height of the sub container for modal
const subContainerHeightRef = useRef(height ?? '100%');
useEffect(() => {
@ -137,24 +126,6 @@ export const SubContainer = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(allChildComponents), parent]);
// useEffect(() => {
// try {
// const isParentScrollable = SUBCONTAINER_WITH_SCROLL.has(allComponents[parent]?.component?.component);
// const canvasBounds = parentRef.current.getBoundingClientRect();
// const subContainerHeight = canvasBounds.height - 30;
// const componentBottom = Object.values(childWidgets).reduce(function (max, currentElement) {
// let currentSum = currentElement.layouts[currentLayout].top + currentElement.layouts[currentLayout].height;
// return Math.max(max, currentSum);
// }, 0);
// if (isParentScrollable && subContainerHeight <= componentBottom) {
// subContainerHeightRef.current = componentBottom + 100;
// }
// } catch (error) {
// console.error('console.error', error);
// }
// }, [childWidgets]);
const containerWidth = getContainerCanvasWidth();
const placeComponentInsideParent = (newComponent, canvasBoundingRect) => {
@ -220,119 +191,6 @@ export const SubContainer = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [containerWidth]);
// useEffect(() => {
// if (mounted) {
// //find children with parent prop
// const children = Object.keys(allComponents).filter((key) => {
// if (key === parent) return false;
// return allComponents[key].parent === parent;
// });
// if (children.length === 0 && addDefaultChildren === true) {
// const defaultChildren = _.cloneDeep(parentComponent)['defaultChildren'];
// const childrenBoxes = {};
// const parentId =
// parentComponent.component !== 'Tabs'
// ? parentRef.current.id
// : parentRef.current.id?.substring(0, parentRef.current.id.lastIndexOf('-'));
// const _allComponents = JSON.parse(JSON.stringify(allComponents));
// defaultChildren.forEach((child) => {
// const { componentName, layout, incrementWidth, properties, accessorKey, tab, defaultValue, styles } = child;
// const componentMeta = _.cloneDeep(componentTypes.find((component) => component.component === componentName));
// const componentData = JSON.parse(JSON.stringify(componentMeta));
// const width = layout.width ? layout.width : (componentMeta.defaultSize.width * 100) / noOfGrids;
// const height = layout.height ? layout.height : componentMeta.defaultSize.height;
// const newComponentDefinition = {
// ...componentData.definition.properties,
// };
// if (_.isArray(properties) && properties.length > 0) {
// properties.forEach((prop) => {
// const accessor = customResolverVariable
// ? `{{${customResolverVariable}.${accessorKey}}}`
// : defaultValue[prop] || '';
// _.set(newComponentDefinition, prop, {
// value: accessor,
// });
// });
// _.set(componentData, 'definition.properties', newComponentDefinition);
// }
// if (_.isArray(styles) && styles.length > 0) {
// styles.forEach((prop) => {
// const accessor = customResolverVariable
// ? `{{${customResolverVariable}.${accessorKey}}}`
// : defaultValue[prop] || '';
// _.set(newComponentDefinition, prop, {
// value: accessor,
// });
// });
// _.set(componentData, 'definition.styles', newComponentDefinition);
// }
// const newComponent = addNewWidgetToTheEditor(
// componentData,
// {},
// { ..._allComponents, ...childrenBoxes },
// {},
// currentLayout,
// snapToGrid,
// zoomLevel,
// true,
// true
// );
// _.set(childrenBoxes, newComponent.id, {
// component: {
// ...newComponent.component,
// parent: parentComponent.component === 'Tabs' ? parentId + '-' + tab : parentId,
// },
// layouts: {
// [currentLayout]: {
// ...layout,
// width: incrementWidth ? width * incrementWidth : width,
// height: height,
// },
// },
// });
// });
// // _allComponents[parentId] = {
// // ...allComponents[parentId],
// // withDefaultChildren: false,
// // };
// const allChildren = getChildWidgets(allComponents);
// setChildWidgets(allChildren);
// // setBoxes({
// // ..._allComponents,
// // ...childrenBoxes,
// // });
// }
// }
// // eslint-disable-next-line react-hooks/exhaustive-deps
// }, [mounted]);
const moveBox = useCallback(
(id, left, top) => {
setChildWidgets(
update(childWidgets, {
[id]: {
$merge: { left, top },
},
})
);
},
[childWidgets]
);
useEffect(() => {
if (appDefinitionChanged) {
const newDefinition = {
@ -369,44 +227,6 @@ export const SubContainer = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [childWidgets]);
// const { draggingState } = useDragLayer((monitor) => {
// // TODO: Need to move to a performant version of the block below
// if (monitor.getItem()) {
// if (monitor.getItem().id === undefined) {
// if (parentRef.current) {
// const currentOffset = monitor.getSourceClientOffset();
// if (currentOffset) {
// const canvasBoundingRect = parentRef?.current
// ?.getElementsByClassName('real-canvas')[0]
// ?.getBoundingClientRect();
// if (!canvasBoundingRect) return { draggingState: false };
// if (
// currentOffset.x > canvasBoundingRect.x &&
// currentOffset.x < canvasBoundingRect.x + canvasBoundingRect.width
// ) {
// return { draggingState: true };
// }
// }
// }
// }
// }
// if (monitor.isDragging() && monitor.getItem().parent) {
// if (monitor.getItem().parent === parent) {
// return { draggingState: true };
// } else {
// return { draggingState: false };
// }
// } else {
// return { draggingState: false };
// }
// });
//!Todo: need to check: this never gets called as draggingState is always false
// useEffect(() => {
// setIsDragging(draggingState);
// }, [draggingState]);
const [{ isOver, isOverCurrent }, drop] = useDrop(
() => ({
accept: ItemTypes.BOX,
@ -415,7 +235,6 @@ export const SubContainer = ({
if (didDrop && !parent) {
return;
}
console.log('---arpit::: drop --- on subcontainer', { item, isOver, isOverCurrent, didDrop });
if (item.component.component === 'PDF' && !isPDFSupported()) {
toast.error(
@ -591,21 +410,17 @@ export const SubContainer = ({
appDefinition,
appDefinitionChanged,
currentState,
// onComponentOptionChanged,
// onComponentOptionsChanged,
appLoading,
zoomLevel,
setSelectedComponent,
removeComponent,
currentLayout,
// deviceWindowWidth,
selectedComponents,
darkMode,
readOnly,
onComponentHover,
hoveredComponent,
sideBarDebugger,
addDefaultChildren,
currentPageId,
childComponents,
};
@ -631,8 +446,6 @@ export const SubContainer = ({
{checkParentVisibility() &&
Object.entries({
...childWidgets,
// ...(resizingComponentId &&
// childWidgets[resizingComponentId] && { resizingComponentId: childWidgets[resizingComponentId] }),
}).map(([key, box]) => {
const canShowInCurrentLayout =
box.component.definition.others[currentLayout === 'mobile' ? 'showOnMobile' : 'showOnDesktop'].value;
@ -685,13 +498,9 @@ export const SubContainer = ({
allComponents={allComponents}
{...box}
mode={mode}
// resizingStatusChanged={(status) => setIsResizing(status)}
// draggingStatusChanged={(status) => setIsDragging(status)}
inCanvas={true}
zoomLevel={zoomLevel}
// setSelectedComponent={setSelectedComponent}
selectedComponent={selectedComponent}
// deviceWindowWidth={deviceWindowWidth}
isSelectedComponent={
mode === 'edit' ? selectedComponents.find((component) => component.id === key) : false
}
@ -703,37 +512,8 @@ export const SubContainer = ({
onComponentHover={onComponentHover}
hoveredComponent={hoveredComponent}
parentId={parent}
// sideBarDebugger={sideBarDebugger}
isMultipleComponentsSelected={selectedComponents?.length > 1 ? true : false}
exposedVariables={exposedVariables ?? {}}
// childComponents={childComponents[key]}
// containerProps={{
// mode,
// snapToGrid,
// onComponentClick,
// onEvent,
// appDefinition,
// appDefinitionChanged,
// currentState,
// onComponentOptionChanged,
// onComponentOptionsChanged,
// appLoading,
// zoomLevel,
// setSelectedComponent,
// removeComponent,
// currentLayout,
// deviceWindowWidth,
// selectedComponents,
// darkMode,
// readOnly,
// onComponentHover,
// hoveredComponent,
// sideBarDebugger,
// addDefaultChildren,
// currentPageId,
// childComponents,
// setSubContainerWidths,
// }}
getContainerProps={getContainerProps}
/>
</SubWidgetWrapper>
@ -758,7 +538,6 @@ export const SubContainer = ({
</center>
</div>
)}
{/* <GhostWidget layout={childWidgets[]} */}
</SubContianerWrapper>
);
};
@ -816,7 +595,7 @@ const SubWidgetWrapper = ({
useEffect(() => {
const controlBox = document.querySelector(`[target-id="${id}"]`);
console.log('controlBox', { hide: !isOnScreen && isSelected && !isDragging && !isResizing, isOnScreen });
// console.log('controlBox', { hide: !isOnScreen && isSelected && !isDragging && !isResizing, isOnScreen });
//adding attribute instead of class since react-moveable seems to replace classes internally on scroll stop
if (!isOnScreen && isSelected && !isDragging && !isResizing) {
controlBox?.classList.add('hide-control');
@ -855,7 +634,6 @@ const SubWidgetWrapper = ({
};
const SubContianerWrapper = ({ children, isDragging, isResizing, isGridActive, readOnly, drop, styles, parent }) => {
// const [dragTarget] = useDragTarget();
return (
<div
ref={drop}
@ -863,7 +641,6 @@ const SubContianerWrapper = ({ children, isDragging, isResizing, isGridActive, r
id={`canvas-${parent}`}
data-parent={parent}
className={`sub-canvas real-canvas ${
// (isDragging || isResizing || dragTarget === parent || isGridActive) && !readOnly ? 'show-grid' : 'hide-grid'
(isDragging || isResizing || isGridActive) && !readOnly ? 'show-grid' : 'hide-grid'
}`}
>

View file

@ -47,8 +47,6 @@ function getItemStyles(delta, item, initialOffset, currentOffset, parentRef, par
[x, y] = snapToGrid(canvasWidth, x, y);
console.log(`translate(${x}px, ${y}px)`);
const transform = `translate(${x}px, ${y}px)`;
return {
transform,

View file

@ -96,6 +96,10 @@ class ViewerComponent extends React.Component {
appDefinition: { ...appDefData },
pages: appDefData.pages,
});
useEditorStore.getState().actions.updateEditorState({
appDefinition: { ...appDefData },
});
};
setStateForContainer = async (data, appVersionId) => {

View file

@ -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',
@ -110,41 +111,40 @@ export function onComponentOptionsChanged(component, options) {
export function onComponentOptionChanged(component, option_name, value) {
const componentName = component.name;
const { isEditorReady } = getCurrentState();
const { isEditorReady, components: currentComponents } = getCurrentState();
const components = duplicateCurrentState === null ? currentComponents : duplicateCurrentState;
let componentData = components[componentName] || {};
componentData[option_name] = value;
const path = option_name ? `components.${componentName}.${option_name}` : null;
if (isEditorReady) {
if (duplicateCurrentState !== null) {
duplicateCurrentState = null;
}
const components = getCurrentState().components;
let componentData = components[componentName];
componentData = componentData || {};
componentData[option_name] = value;
if (option_name !== 'id') {
useCurrentStateStore.getState().actions.setCurrentState({
components: { ...components, [componentName]: componentData },
});
} else if (!componentData?.id) {
useCurrentStateStore.getState().actions.setCurrentState({
components: { ...components, [componentName]: componentData },
});
}
// Always update the current state if editor is ready
useCurrentStateStore.getState().actions.setCurrentState({
components: { ...components, [componentName]: componentData },
});
} else {
const components = duplicateCurrentState === null ? getCurrentState().components : duplicateCurrentState;
let componentData = components[componentName];
componentData = componentData || {};
componentData[option_name] = value;
duplicateCurrentState = { ...components, [componentName]: componentData };
if (option_name !== 'id') {
debouncedChange();
} else if (!componentData?.id) {
debouncedChange();
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 };
debouncedChange();
}
return Promise.resolve();
@ -1112,6 +1112,14 @@ export function runQuery(
},
errors: {},
});
useResolveStore.getState().actions.addAppSuggestions({
queries: {
[queryName]: {
data: [],
isLoading: true,
},
},
});
}
let queryExecutionPromise = null;
if (query.kind === 'runjs') {
@ -1288,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);
}

View file

@ -178,3 +178,21 @@ export function handleLowPriorityWork(callback, timeout = null) {
const options = timeout ? { timeout } : {};
window.requestIdleCallback(callback, options);
}
export function generatePath(obj, targetKey, currentPath = '') {
for (const key in obj) {
const newPath = currentPath ? currentPath + '.' + key : key;
if (key === targetKey) {
return newPath;
}
if (typeof obj[key] === 'object' && obj[key] !== null) {
const result = generatePath(obj[key], targetKey, newPath);
if (result) {
return result;
}
}
}
return null;
}

View file

@ -0,0 +1,18 @@
import React, { Profiler } from 'react';
export const withProfiler = (WrappedComponent) => (props) => {
function onRenderCallback(id, phase, actualDuration, baseDuration, startTime, commitTime) {
const markName = `${id} (${phase})`;
performance.measure(markName, {
end: commitTime,
start: startTime,
});
performance.clearMeasures(markName);
}
return (
<Profiler id={WrappedComponent.name} onRender={onRenderCallback}>
<WrappedComponent {...props} />
</Profiler>
);
};

View file

@ -12,7 +12,7 @@ function useRenderCount(componentName) {
renderCountRef.current++;
console.log(`CountingRender- Component ${componentName} rendered ${renderCountRef.current} times.`);
// return renderCountRef.current;
return renderCountRef.current;
}
export default useRenderCount;

View file

@ -1,6 +1,6 @@
import { shallow } from 'zustand/shallow';
import { create, zustandDevTools } from './utils';
import _, { omit } from 'lodash';
import _, { debounce, merge, omit } from 'lodash';
import { useResolveStore } from './resolverStore';
// eslint-disable-next-line import/no-unresolved
import { diff } from 'deep-object-diff';
@ -50,45 +50,7 @@ export const useCurrentStateStore = create(
...initialState,
actions: {
setCurrentState: (currentState) => {
const currentStateEntites = Object.keys(currentState);
const existingStateOfEntities = currentStateEntites.reduce((acc, entity) => {
acc[entity] = get()[entity];
return acc;
}, {});
const diffState = diff(existingStateOfEntities, currentState);
if (_.isEmpty(diffState)) return;
set({ ...currentState }, false, { type: 'SET_CURRENT_STATE', currentState });
//need to track only queries, components, variables, page, constants, layout
// from the diff, if any of these entities are changed, we need to update the store
if (get().isEditorReady) {
const entitiesToTrack = ['queries', 'components', 'variables', 'page', 'constants', 'layout'];
const entitiesChanged = Object.keys(diffState).filter((entity) => entitiesToTrack.includes(entity));
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}`).join(',');
return acc;
}, {});
const currentStatePaths = Object.values(allPaths);
useEditorStore.getState().actions.updateCurrentStateDiff(currentStatePaths);
}
},
setErrors: (error) => {
set({ errors: { ...get().errors, ...error } }, false, { type: 'SET_ERRORS', error });

View file

@ -1,27 +0,0 @@
import { create, zustandDevTools } from './utils';
const initialState = {
errors: {},
succededQuery: {},
};
export const useDebuggerStore = create(
zustandDevTools(
(set, get) => ({
...initialState,
actions: {
setErrors: (error) => {
set({ errors: { ...get().errors, ...error } }, false, { type: 'SET_ERRORS', error });
},
clearErrors: () => set({ errors: {} }, false, { type: 'CLEAR_ERRORS' }),
setSuccededQuery: (queryDetails) => {
set({ succededQuery: { ...get().succededQuery, ...queryDetails } }, false, {
type: 'SET_SUCCEDED_QUERY',
queryDetails,
});
},
},
}),
{ name: 'Debugger Store' }
)
);

View file

@ -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 = [];
@ -36,7 +37,6 @@ const initialState = {
queryConfirmationList: [],
currentPageId: null,
currentSessionId: uuid(),
currentStateDiff: [],
componentsNeedsUpdateOnNextRender: [],
};
@ -64,9 +64,18 @@ export const useEditorStore = create(
setIsEditorActive: (isEditorActive) => set(() => ({ isEditorActive })),
updateEditorState: (state) => set((prev) => ({ ...prev, ...state })),
updateCurrentStateDiff: (currentStateDiff) => set(() => ({ currentStateDiff })),
updateComponentsNeedsUpdateOnNextRender: (componentsNeedsUpdateOnNextRender) =>
set(() => ({ componentsNeedsUpdateOnNextRender })),
flushComponentsNeedsUpdateOnNextRender: () => set(() => ({ componentsNeedsUpdateOnNextRender: [] })),
updateComponentsNeedsUpdateOnNextRender: (componentsNeedsUpdateOnNextRender) => {
set(() => ({ componentsNeedsUpdateOnNextRender }));
},
flushComponentsNeedsUpdateOnNextRender: (toRemoveIds = []) => {
const currentComponents = get().componentsNeedsUpdateOnNextRender;
if (currentComponents.length === 0 || toRemoveIds.length === 0) return;
const updatedComponents = currentComponents.filter((item) => !toRemoveIds.includes(item));
set(() => ({ componentsNeedsUpdateOnNextRender: updatedComponents }));
},
updateQueryConfirmationList: (queryConfirmationList) => set({ queryConfirmationList }),
setHoveredComponent: (hoveredComponent) =>
@ -105,6 +114,9 @@ export const getComponentsToRenders = () => {
return useEditorStore.getState().componentsNeedsUpdateOnNextRender;
};
export const flushComponentsToRender = () => {
useEditorStore.getState().actions.flushComponentsNeedsUpdateOnNextRender();
export const flushComponentsToRender = (componentIds = []) => {
if (!componentIds.length) return;
useEditorStore.getState().actions.flushComponentsNeedsUpdateOnNextRender(componentIds);
useResolveStore.getState().actions.getLastUpdatedRefs();
};

View file

@ -1,5 +1,5 @@
import { create, zustandDevTools } from './utils';
import { shallow } from 'zustand/shallow';
import { useDataQueriesStore } from '@/_stores/dataQueriesStore';
const queryManagerPreferences = JSON.parse(localStorage.getItem('queryManagerPreferences')) ?? {};

View file

@ -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 } }));

View file

@ -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 });
}

View file

@ -1,7 +1,6 @@
// import './wdyr'; // <--- first import
import React from 'react';
import { render } from 'react-dom';
// import { createRoot } from 'react-dom/client';
import * as Sentry from '@sentry/react';
import { useLocation, useNavigationType, createRoutesFromChildren, matchRoutes } from 'react-router-dom';
import { appService } from '@/_services';
@ -9,7 +8,7 @@ import { App } from './App';
// eslint-disable-next-line import/no-unresolved
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
// import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend';
const AppWithProfiler = Sentry.withProfiler(App);