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/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3", "@testing-library/user-event": "^14.4.3",
"@welldone-software/why-did-you-render": "^8.0.1",
"babel-loader": "^9.1.2", "babel-loader": "^9.1.2",
"babel-plugin-console-source": "^2.0.5", "babel-plugin-console-source": "^2.0.5",
"babel-plugin-import": "^1.13.6", "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": { "node_modules/@xtuc/ieee754": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "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/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3", "@testing-library/user-event": "^14.4.3",
"@welldone-software/why-did-you-render": "^8.0.1",
"babel-loader": "^9.1.2", "babel-loader": "^9.1.2",
"babel-plugin-console-source": "^2.0.5", "babel-plugin-console-source": "^2.0.5",
"babel-plugin-import": "^1.13.6", "babel-plugin-import": "^1.13.6",

View file

@ -2,6 +2,8 @@ import React from 'react';
import HydrateWithResolveReferences from './Middlewares/HydrateWithResolveReferences'; import HydrateWithResolveReferences from './Middlewares/HydrateWithResolveReferences';
import BoxUI from './BoxUI'; import BoxUI from './BoxUI';
import _ from 'lodash'; import _ from 'lodash';
import { useEditorStore } from '@/_stores/editorStore';
import { shallow } from 'zustand/shallow';
function deepEqualityCheckusingLoDash(obj1, obj2) { function deepEqualityCheckusingLoDash(obj1, obj2) {
return _.isEqual(obj1, obj2); return _.isEqual(obj1, obj2);
@ -19,6 +21,12 @@ export const shouldUpdate = (prevProps, nextProps) => {
export const Box = (props) => { export const Box = (props) => {
const { id, component, mode, customResolvables } = 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 ( return (
<HydrateWithResolveReferences id={id} mode={mode} component={component} customResolvables={customResolvables}> <HydrateWithResolveReferences id={id} mode={mode} component={component} customResolvables={customResolvables}>
<BoxUI {...props} /> <BoxUI {...props} />

View file

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

View file

@ -95,7 +95,6 @@ export function CodeBuilder({ initialValue, onChange, components }) {
return { item: item }; return { item: item };
}); });
} else { } else {
console.log(currentWord);
filteredVariables = fuse.search(currentWord); filteredVariables = fuse.search(currentWord);
} }
return filteredVariables.map((variable) => renderVariable(type, key, variable.item.name)); 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-'))) { if (fxActive && (value.startsWith('#') || value.includes('table-'))) {
value = JSON.stringify(value); value = JSON.stringify(value);
} }
const { toResolveReference, jsExpression, jsExpMatch } = inferJSExpAndReferences(value, lookupTable.hints); 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); const idToLookUp = lookupTable.hints.get(toResolveReference);
resolvedValue = lookupTable.resolvedRefs.get(idToLookUp); resolvedValue = lookupTable.resolvedRefs.get(idToLookUp);

View file

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

View file

@ -128,9 +128,7 @@ export const Container = ({
: updatedBoxes[id].layouts.desktop; : updatedBoxes[id].layouts.desktop;
}); });
setBoxes({ ...updatedBoxes }); setBoxes({ ...updatedBoxes });
// console.log('currentLayout', data);
} }
// setNoOfGrids(currentLayout === 'mobile' ? 12 : 43);
}, [currentLayout]); }, [currentLayout]);
const paramUpdatesOptsRef = useRef({}); const paramUpdatesOptsRef = useRef({});
@ -316,10 +314,6 @@ export const Container = ({
[setCanvasHeight, currentLayout, mode] [setCanvasHeight, currentLayout, mode]
); );
// useEffect(() => {
// setIsDragging(draggingState);
// }, [draggingState]);
const [{ isOver, isOverCurrent }, drop] = useDrop( const [{ isOver, isOverCurrent }, drop] = useDrop(
() => ({ () => ({
accept: ItemTypes.BOX, accept: ItemTypes.BOX,
@ -372,6 +366,86 @@ export const Container = ({
zoomLevel 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 = { const newBoxes = {
...boxes, ...boxes,
[newComponent.id]: { [newComponent.id]: {
@ -379,8 +453,8 @@ export const Container = ({
layouts: { layouts: {
...newComponent.layout, ...newComponent.layout,
}, },
withDefaultChildren: newComponent.withDefaultChildren,
}, },
...childrenBoxes,
}; };
setBoxes(newBoxes); setBoxes(newBoxes);
@ -445,8 +519,6 @@ export const Container = ({
setBoxes(updatedBoxes); setBoxes(updatedBoxes);
updateCanvasHeight(updatedBoxes); updateCanvasHeight(updatedBoxes);
}; };
// [boxes, updateCanvasHeight, canvasWidth, gridWidth, currentLayout]
// );
function onDragStop(boxPositions) { function onDragStop(boxPositions) {
const copyOfBoxes = JSON.parse(JSON.stringify(boxes)); const copyOfBoxes = JSON.parse(JSON.stringify(boxes));
@ -679,8 +751,6 @@ export const Container = ({
}, [components]); }, [components]);
const getContainerProps = React.useCallback((componentId) => { const getContainerProps = React.useCallback((componentId) => {
const withDefaultChildren = boxes[componentId]?.withDefaultChildren;
return { return {
mode, mode,
snapToGrid, snapToGrid,
@ -696,7 +766,6 @@ export const Container = ({
currentLayout, currentLayout,
selectedComponents, selectedComponents,
darkMode, darkMode,
addDefaultChildren: withDefaultChildren,
currentPageId, currentPageId,
childComponents: childComponents[componentId], childComponents: childComponents[componentId],
parentGridWidth: gridWidth, parentGridWidth: gridWidth,
@ -785,6 +854,7 @@ export const Container = ({
isMultipleComponentsSelected={selectedComponents?.length > 1 ? true : false} isMultipleComponentsSelected={selectedComponents?.length > 1 ? true : false}
getContainerProps={getContainerProps} getContainerProps={getContainerProps}
isVersionReleased={isVersionReleased} isVersionReleased={isVersionReleased}
currentPageId={currentPageId}
/> />
</WidgetWrapper> </WidgetWrapper>
); );
@ -803,10 +873,7 @@ export const Container = ({
onDrag={onDragStop} onDrag={onDragStop}
gridWidth={gridWidth} gridWidth={gridWidth}
selectedComponents={selectedComponents} selectedComponents={selectedComponents}
// setIsDragging={setIsDragging}
// setIsResizing={setIsResizing}
currentLayout={currentLayout} currentLayout={currentLayout}
// subContainerWidths={subContainerWidths}
currentPageId={currentPageId} currentPageId={currentPageId}
draggedSubContainer={draggedSubContainer} draggedSubContainer={draggedSubContainer}
mode={isVersionReleased ? 'view' : mode} mode={isVersionReleased ? 'view' : mode}
@ -862,7 +929,6 @@ const WidgetWrapper = ({ children, widget, id, gridWidth, currentLayout, isResiz
width: width + 'px', width: width + 'px',
height: layoutData.height + 'px', height: layoutData.height + 'px',
transform: `translate(${layoutData.left * gridWidth}px, ${layoutData.top}px)`, transform: `translate(${layoutData.left * gridWidth}px, ${layoutData.top}px)`,
// ...(isGhostComponent ? { opacity: 0.5 } : isResizing ? { opacity: 0 } : {}),
...(isGhostComponent ? { opacity: 0.5 } : {}), ...(isGhostComponent ? { opacity: 0.5 } : {}),
...(isWidgetActive ? { zIndex: 3 } : {}), ...(isWidgetActive ? { zIndex: 3 } : {}),
}; };
@ -907,18 +973,7 @@ function DragGhostWidget() {
); );
} }
function ContainerWrapper({ function ContainerWrapper({ children, canvasHeight, isDropping, showComments, handleAddThread, containerRef, styles }) {
children,
canvasHeight,
// isDragging,
// isResizing,
isDropping,
showComments,
handleAddThread,
containerRef,
styles,
}) {
// const [dragTarget] = useDragTarget();
const { resizingComponentId, draggingComponentId, dragTarget } = useGridStore((state) => { const { resizingComponentId, draggingComponentId, dragTarget } = useGridStore((state) => {
const { resizingComponentId, draggingComponentId, dragTarget } = state; const { resizingComponentId, draggingComponentId, dragTarget } = state;
return { resizingComponentId, draggingComponentId, dragTarget }; return { resizingComponentId, draggingComponentId, dragTarget };
@ -930,7 +985,6 @@ function ContainerWrapper({
ref={containerRef} ref={containerRef}
style={{ ...styles, height: canvasHeight }} style={{ ...styles, height: canvasHeight }}
className={cx('real-canvas', { className={cx('real-canvas', {
// 'show-grid': isDragging || isResizing || dragTarget === 'canvas',
'show-grid': (!!resizingComponentId && !dragTarget) || (!!draggingComponentId && !dragTarget) || isDropping, 'show-grid': (!!resizingComponentId && !dragTarget) || (!!draggingComponentId && !dragTarget) || isDropping,
})} })}
id="real-canvas" 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 { getComponentToRender } from '@/_helpers/editorHelpers';
import _ from 'lodash'; import _ from 'lodash';
import { flushComponentsToRender, getComponentsToRenders } from '@/_stores/editorStore'; import { getComponentsToRenders } from '@/_stores/editorStore';
function deepEqualityCheckusingLoDash(obj1, obj2) { function deepEqualityCheckusingLoDash(obj1, obj2) {
return _.isEqual(obj1, obj2); return _.isEqual(obj1, obj2);
@ -17,6 +17,7 @@ export const shouldUpdate = (prevProps, nextProps) => {
if (componentId) { if (componentId) {
const componentToRender = listToRender.find((item) => item === componentId); const componentToRender = listToRender.find((item) => item === componentId);
if (componentToRender) { if (componentToRender) {
needToRender = true; needToRender = true;
} }
@ -34,15 +35,6 @@ export const shouldUpdate = (prevProps, nextProps) => {
const ComponentWrapper = React.memo(({ componentName, ...props }) => { const ComponentWrapper = React.memo(({ componentName, ...props }) => {
const ComponentToRender = getComponentToRender(componentName); const ComponentToRender = getComponentToRender(componentName);
const [shouldFlush, setShouldFlush] = useState(false);
useEffect(() => {
if (shouldFlush) {
flushComponentsToRender();
setShouldFlush(false); // Reset the condition
}
}, [shouldFlush]);
return <ComponentToRender {...props} />; return <ComponentToRender {...props} />;
}, shouldUpdate); }, shouldUpdate);

View file

@ -24,10 +24,7 @@ export default function DragContainer({
onDrag, onDrag,
gridWidth, gridWidth,
selectedComponents = [], selectedComponents = [],
// setIsDragging,
// setIsResizing,
currentLayout, currentLayout,
// subContainerWidths,
draggedSubContainer, draggedSubContainer,
}) { }) {
const lastDraggedEventsRef = useRef(null); 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 moveableRef = useRef();
const draggedOverElemRef = useRef(null); const draggedOverElemRef = useRef(null);
const childMoveableRefs = useRef({}); const childMoveableRefs = useRef({});
@ -171,7 +166,6 @@ export default function DragContainer({
console.error('Error---->', error); console.error('Error---->', error);
} }
}, [hoveredComponent, reloadGrid]); }, [hoveredComponent, reloadGrid]);
// }, [JSON.stringify(selectedComponents), JSON.stringify(boxes), hoveredComponent]);
useEffect(() => { useEffect(() => {
setList(boxList); setList(boxList);
@ -233,16 +227,12 @@ export default function DragContainer({
} }
}, [selectedComponents]); }, [selectedComponents]);
// window.reloadGrid = reloadGrid;
useEffect(() => { useEffect(() => {
setList(boxList); setList(boxList);
}, [JSON.stringify(boxes)]); }, [JSON.stringify(boxes)]);
const groupedTargets = [ const groupedTargets = [
...findHighestLevelofSelection(selectedComponents) ...findHighestLevelofSelection(selectedComponents).map((component) => '.ele-' + component.id),
// .filter((component) => !component?.component?.parent)
.map((component) => '.ele-' + component.id),
]; ];
useEffect(() => { useEffect(() => {
@ -257,8 +247,6 @@ export default function DragContainer({
lastDraggedEventsRef.current = posWithParent; lastDraggedEventsRef.current = posWithParent;
}; };
// const handleResize = useCallback((e) => handleWidgetResize(e, list, boxes, gridWidth), [list, boxes, gridWidth]);
return mode === 'edit' ? ( return mode === 'edit' ? (
<> <>
<Moveable <Moveable
@ -386,12 +374,7 @@ export default function DragContainer({
onResizeStart={(e) => { onResizeStart={(e) => {
performance.mark('onResizeStart'); performance.mark('onResizeStart');
useGridStore.getState().actions.setResizingComponentId(e.target.id); useGridStore.getState().actions.setResizingComponentId(e.target.id);
// setIsResizing(true);
e.setMin([gridWidth, 10]); e.setMin([gridWidth, 10]);
// if (currentLayout === 'mobile' && autoComputeLayout) {
// turnOffAutoLayout();
// return false;
// }
}} }}
onResizeGroupStart={({ events }) => { onResizeGroupStart={({ events }) => {
const parentElm = events[0].target.closest('.real-canvas'); const parentElm = events[0].target.closest('.real-canvas');
@ -500,15 +483,12 @@ export default function DragContainer({
if (hoveredComponent !== e.target.id) { if (hoveredComponent !== e.target.id) {
return false; return false;
} }
// setDraggedTarget(e.target.id);
}} }}
onDragEnd={(e) => { onDragEnd={(e) => {
try { try {
if (isDraggingRef.current) { if (isDraggingRef.current) {
// setTimeout(() => useGridStore.getState().actions.setDraggingComponentId(null));
useGridStore.getState().actions.setDraggingComponentId(null); useGridStore.getState().actions.setDraggingComponentId(null);
isDraggingRef.current = false; isDraggingRef.current = false;
// setIsDragging(false);
} }
if (draggedSubContainer) { if (draggedSubContainer) {
@ -612,20 +592,16 @@ export default function DragContainer({
element.classList.remove('show-grid'); element.classList.remove('show-grid');
element.classList.add('hide-grid'); element.classList.add('hide-grid');
}); });
// setDraggedTarget();
}} }}
onDrag={(e) => { onDrag={(e) => {
if (!isDraggingRef.current) { if (!isDraggingRef.current) {
useGridStore.getState().actions.setDraggingComponentId(e.target.id); useGridStore.getState().actions.setDraggingComponentId(e.target.id);
isDraggingRef.current = true; isDraggingRef.current = true;
// setIsDragging(true);
} }
if (draggedSubContainer) { if (draggedSubContainer) {
return; return;
} }
// if (e.target.id !== draggedTarget) {
// setDraggedTarget(e.target.id);
// }
if (!draggedSubContainer) { if (!draggedSubContainer) {
const parentComponent = widgets[widgets[e.target.id]?.component?.parent]; const parentComponent = widgets[widgets[e.target.id]?.component?.parent];
let top = e.translate[1]; let top = e.translate[1];
@ -667,7 +643,7 @@ export default function DragContainer({
}); });
const parentWidgetId = draggedOverContainer.getAttribute('data-parent') || draggedOverElem?.id; const parentWidgetId = draggedOverContainer.getAttribute('data-parent') || draggedOverElem?.id;
document.getElementById('canvas-' + parentWidgetId)?.classList.add('show-grid'); document.getElementById('canvas-' + parentWidgetId)?.classList.add('show-grid');
console.log('dragTarget-- parentWidgetId', parentWidgetId);
useGridStore.getState().actions.setDragTarget(parentWidgetId); useGridStore.getState().actions.setDragTarget(parentWidgetId);
if ( if (
@ -679,7 +655,7 @@ export default function DragContainer({
draggedOverElemRef.current = draggedOverContainer; draggedOverElemRef.current = draggedOverContainer;
} }
} }
console.log('getOffset--', getOffset(e.target, document.querySelector('#real-canvas')));
const offset = getOffset(e.target, document.querySelector('#real-canvas')); const offset = getOffset(e.target, document.querySelector('#real-canvas'));
if (document.getElementById('moveable-drag-ghost')) { if (document.getElementById('moveable-drag-ghost')) {
document.getElementById('moveable-drag-ghost').style.transform = `translate(${offset.x}px, ${offset.y}px)`; 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 }; 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 * as Sentry from '@sentry/react';
import { findHighestLevelofSelection } from './DragContainer'; import { findHighestLevelofSelection } from './DragContainer';
// const noOfGrid = 43;
function computeWidth(currentLayoutOptions) { function computeWidth(currentLayoutOptions) {
return `${currentLayoutOptions?.width}%`; return `${currentLayoutOptions?.width}%`;
} }
@ -54,6 +52,7 @@ const DraggableBox = React.memo(
customResolvables, customResolvables,
parentId, parentId,
getContainerProps, getContainerProps,
currentPageId,
}) => { }) => {
const isResizing = useGridStore((state) => state.resizingComponentId === id); const isResizing = useGridStore((state) => state.resizingComponentId === id);
const [canDrag, setCanDrag] = useState(true); const [canDrag, setCanDrag] = useState(true);
@ -222,6 +221,7 @@ const DraggableBox = React.memo(
customResolvables={customResolvables} customResolvables={customResolvables}
parentId={parentId} parentId={parentId}
getContainerProps={getContainerProps} getContainerProps={getContainerProps}
currentPageId={currentPageId}
/> />
</Sentry.ErrorBoundary> </Sentry.ErrorBoundary>
</div> </div>
@ -238,9 +238,4 @@ const DraggableBox = React.memo(
} }
); );
// DraggableBox.whyDidYouRender = {
// logOnDifferentValues: true,
// customName: 'WDYRDraggableBox',
// };
export { DraggableBox }; export { DraggableBox };

View file

@ -70,7 +70,7 @@ import {
resetAllStores, resetAllStores,
} from '@/_stores/utils'; } from '@/_stores/utils';
import { setCookie } from '@/_helpers/cookie'; 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 { useAppDataActions, useAppDataStore } from '@/_stores/appDataStore';
import { useNoOfGrid } from '@/_stores/gridStore'; import { useNoOfGrid } from '@/_stores/gridStore';
import { useMounted } from '@/_hooks/use-mount'; import { useMounted } from '@/_hooks/use-mount';
@ -89,7 +89,7 @@ import { HotkeysProvider } from 'react-hotkeys-hook';
import { useResolveStore } from '@/_stores/resolverStore'; import { useResolveStore } from '@/_stores/resolverStore';
import { dfs } from '@/_stores/handleReferenceTransactions'; import { dfs } from '@/_stores/handleReferenceTransactions';
import { decimalToHex } from './editorConstants'; import { decimalToHex } from './editorConstants';
import { findComponentsWithReferences, handleLowPriorityWork } from '@/_helpers/editorHelpers'; import { findComponentsWithReferences, generatePath, handleLowPriorityWork } from '@/_helpers/editorHelpers';
setAutoFreeze(false); setAutoFreeze(false);
enablePatches(); enablePatches();
@ -212,7 +212,8 @@ const EditorComponent = (props) => {
const selectionRef = useRef(null); const selectionRef = useRef(null);
const prevAppDefinition = useRef(appDefinition); const prevAppDefinition = useRef(appDefinition);
const prevEventsStoreRef = useRef(events);
const onAppLoadAndPageLoadEventsAreTriggered = useRef(false);
useLayoutEffect(() => { useLayoutEffect(() => {
resetAllStores(); resetAllStores();
@ -287,27 +288,57 @@ const EditorComponent = (props) => {
if (appDiffOptions?.skipAutoSave === true || appDiffOptions?.entityReferenceUpdated === true) return; if (appDiffOptions?.skipAutoSave === true || appDiffOptions?.entityReferenceUpdated === true) return;
if (useEditorStore.getState().isUpdatingEditorStateInProcess) { handleLowPriorityWork(() => autoSave());
handleLowPriorityWork(() => autoSave());
}
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify({ appDefinition, currentPageId, dataQueries })]); }, [JSON.stringify({ appDefinition, currentPageId, dataQueries })]);
const currentStateDiff = useEditorStore.getState().currentStateDiff; const prevCurrentStateRef = useRef(currentState);
useEffect(() => {
const isEditorReady = useCurrentStateStore.getState().isEditorReady;
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 currentComponents = useEditorStore.getState().appDefinition?.pages?.[currentPageId]?.components || {};
const componentIdsWithReferences = findComponentsWithReferences(currentComponents, currentStateDiff); const componentIdsWithReferences = findComponentsWithReferences(currentComponents, lastUpdatedRef);
if (componentIdsWithReferences.length > 0) { if (componentIdsWithReferences.length > 0) {
updateComponentsNeedsUpdateOnNextRender(componentIdsWithReferences); batchUpdateComponents(componentIdsWithReferences);
} }
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(currentStateDiff)]); }, [lastUpdatedRef]);
useEffect( useEffect(
() => { () => {
@ -345,14 +376,6 @@ const EditorComponent = (props) => {
} }
}, [currentLayout, mounted]); }, [currentLayout, mounted]);
const handleYmapEventUpdates = () => {
props.ymap?.set('eventHandlersUpdated', {
currentVersionId: currentVersionId,
currentSessionId: currentSessionId,
update: true,
});
};
const handleMessage = (event) => { const handleMessage = (event) => {
const { data } = event; const { data } = event;
@ -482,11 +505,6 @@ const EditorComponent = (props) => {
socket?.addEventListener('message', (event) => { socket?.addEventListener('message', (event) => {
const data = event.data.replace(/^"(.+(?="$))"$/, '$1'); const data = event.data.replace(/^"(.+(?="$))"$/, '$1');
if (data === 'versionReleased') fetchApp(); 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 handleQueryPaneDragging = (bool) => setIsQueryPaneDragging(bool);
const handleQueryPaneExpanding = (bool) => setIsQueryPaneExpanded(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) => { const changeDarkMode = (newMode) => {
useCurrentStateStore.getState().actions.setCurrentState({ useCurrentStateStore.getState().actions.setCurrentState({
globals: { globals: {
@ -624,16 +634,9 @@ const EditorComponent = (props) => {
props.switchDarkMode(newMode); 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) => { const handleEvent = React.useCallback((eventName, event, options) => {
return onEvent(getEditorRef(), eventName, event, options, 'edit'); return onEvent(getEditorRef(), eventName, event, options, 'edit');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
const handleRunQuery = (queryId, queryName) => runQuery(getEditorRef(), queryId, queryName); const handleRunQuery = (queryId, queryName) => runQuery(getEditorRef(), queryId, queryName);
@ -672,7 +675,6 @@ const EditorComponent = (props) => {
}; };
const getPagesWithIds = () => { const getPagesWithIds = () => {
//! Needs attention
return Object.entries(appDefinition?.pages).map(([id, page]) => ({ ...page, id })); return Object.entries(appDefinition?.pages).map(([id, page]) => ({ ...page, id }));
}; };
@ -741,13 +743,12 @@ const EditorComponent = (props) => {
useCurrentStateStore.getState().actions.setCurrentState({ useCurrentStateStore.getState().actions.setCurrentState({
page: currentpageData, page: currentpageData,
}); }),
updateEditorState({
updateEditorState({ isLoading: false,
isLoading: false, appDefinition: appJson,
appDefinition: appJson, isUpdatingEditorStateInProcess: false,
isUpdatingEditorStateInProcess: false, });
});
updateState({ components: appJson.pages[homePageId]?.components }); updateState({ components: appJson.pages[homePageId]?.components });
@ -898,6 +899,7 @@ const EditorComponent = (props) => {
handleLowPriorityWork(async () => { handleLowPriorityWork(async () => {
await runQueries(useDataQueriesStore.getState().dataQueries, editorRef, true); await runQueries(useDataQueriesStore.getState().dataQueries, editorRef, true);
await handleEvent('onPageLoad', currentPageEvents, {}, true); await handleEvent('onPageLoad', currentPageEvents, {}, true);
await handleLowPriorityWork(() => (onAppLoadAndPageLoadEventsAreTriggered.current = true));
}); });
}); });
}; };

View file

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

View file

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

View file

@ -1,7 +1,7 @@
/* eslint-disable import/no-named-as-default */ /* 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 { useDrop } from 'react-dnd';
import { EditorConstants, ItemTypes } from './editorConstants'; import { ItemTypes } from './editorConstants';
import { DraggableBox } from './DraggableBox'; import { DraggableBox } from './DraggableBox';
import update from 'immutability-helper'; import update from 'immutability-helper';
import _, { isEmpty } from 'lodash'; import _, { isEmpty } from 'lodash';
@ -21,23 +21,17 @@ import { useGridStore, useResizingComponentId } from '@/_stores/gridStore';
import { isPDFSupported } from '@/_stores/utils'; import { isPDFSupported } from '@/_stores/utils';
import GhostWidget from './GhostWidget'; import GhostWidget from './GhostWidget';
const deviceWindowWidth = EditorConstants.deviceWindowWidth;
export const SubContainer = ({ export const SubContainer = ({
mode, mode,
snapToGrid, snapToGrid,
onComponentClick, onComponentClick,
onEvent, onEvent,
// appDefinition,
appDefinitionChanged, appDefinitionChanged,
// onComponentOptionChanged,
// onComponentOptionsChanged,
appLoading, appLoading,
zoomLevel, zoomLevel,
parent, parent,
parentRef, parentRef,
setSelectedComponent, setSelectedComponent,
// deviceWindowWidth,
selectedComponent, selectedComponent,
currentLayout, currentLayout,
removeComponent, removeComponent,
@ -51,25 +45,21 @@ export const SubContainer = ({
sideBarDebugger, sideBarDebugger,
onOptionChange, onOptionChange,
exposedVariables, exposedVariables,
addDefaultChildren = false,
height = '100%', height = '100%',
currentPageId, currentPageId,
childComponents = null, childComponents = null,
listmode = null, listmode = null,
columns = 1, columns = 1,
// setSubContainerWidths,
parentWidgetId, parentWidgetId,
// turnOffAutoLayout,
}) => { }) => {
//Todo add custom resolve vars for other widgets too //Todo add custom resolve vars for other widgets too
const mounted = useMounted();
const widgetResolvables = Object.freeze({ const widgetResolvables = Object.freeze({
Listview: 'listItem', Listview: 'listItem',
}); });
const appDefinition = useEditorStore((state) => state.appDefinition, shallow); const appDefinition = useEditorStore((state) => state.appDefinition, shallow);
const customResolverVariable = widgetResolvables[parentComponent?.component];
const currentState = useCurrentState(); const currentState = useCurrentState();
const { selectedComponents } = useEditorStore( const { selectedComponents } = useEditorStore(
(state) => ({ (state) => ({
@ -80,7 +70,6 @@ export const SubContainer = ({
const resizingComponentId = useResizingComponentId(); const resizingComponentId = useResizingComponentId();
// const [noOfGrids] = useNoOfGrid();
const noOfGrids = 43; const noOfGrids = 43;
const { isGridActive } = useGridStore((state) => ({ isGridActive: state.activeGrid === parent }), shallow); const { isGridActive } = useGridStore((state) => ({ isGridActive: state.activeGrid === parent }), shallow);
@ -97,6 +86,7 @@ export const SubContainer = ({
zoomLevel = zoomLevel || 1; zoomLevel = zoomLevel || 1;
// eslint-disable-next-line react-hooks/exhaustive-deps
const allComponents = appDefinition.pages[currentPageId]?.components ?? {}; const allComponents = appDefinition.pages[currentPageId]?.components ?? {};
const allChildComponents = useMemo(() => { const allChildComponents = useMemo(() => {
@ -110,11 +100,10 @@ export const SubContainer = ({
return _childWidgets; return _childWidgets;
}, [allComponents, parent]); }, [allComponents, parent]);
// const [boxes, setBoxes] = useState(allComponents);
const [childWidgets, setChildWidgets] = useState(() => allChildComponents); const [childWidgets, setChildWidgets] = useState(() => allChildComponents);
const [isDragging, setIsDragging] = useState(false); const [isDragging, setIsDragging] = useState(false);
const [isResizing, setIsResizing] = 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%'); const subContainerHeightRef = useRef(height ?? '100%');
useEffect(() => { useEffect(() => {
@ -137,24 +126,6 @@ export const SubContainer = ({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(allChildComponents), parent]); }, [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 containerWidth = getContainerCanvasWidth();
const placeComponentInsideParent = (newComponent, canvasBoundingRect) => { const placeComponentInsideParent = (newComponent, canvasBoundingRect) => {
@ -220,119 +191,6 @@ export const SubContainer = ({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [containerWidth]); }, [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(() => { useEffect(() => {
if (appDefinitionChanged) { if (appDefinitionChanged) {
const newDefinition = { const newDefinition = {
@ -369,44 +227,6 @@ export const SubContainer = ({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [childWidgets]); }, [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( const [{ isOver, isOverCurrent }, drop] = useDrop(
() => ({ () => ({
accept: ItemTypes.BOX, accept: ItemTypes.BOX,
@ -415,7 +235,6 @@ export const SubContainer = ({
if (didDrop && !parent) { if (didDrop && !parent) {
return; return;
} }
console.log('---arpit::: drop --- on subcontainer', { item, isOver, isOverCurrent, didDrop });
if (item.component.component === 'PDF' && !isPDFSupported()) { if (item.component.component === 'PDF' && !isPDFSupported()) {
toast.error( toast.error(
@ -591,21 +410,17 @@ export const SubContainer = ({
appDefinition, appDefinition,
appDefinitionChanged, appDefinitionChanged,
currentState, currentState,
// onComponentOptionChanged,
// onComponentOptionsChanged,
appLoading, appLoading,
zoomLevel, zoomLevel,
setSelectedComponent, setSelectedComponent,
removeComponent, removeComponent,
currentLayout, currentLayout,
// deviceWindowWidth,
selectedComponents, selectedComponents,
darkMode, darkMode,
readOnly, readOnly,
onComponentHover, onComponentHover,
hoveredComponent, hoveredComponent,
sideBarDebugger, sideBarDebugger,
addDefaultChildren,
currentPageId, currentPageId,
childComponents, childComponents,
}; };
@ -631,8 +446,6 @@ export const SubContainer = ({
{checkParentVisibility() && {checkParentVisibility() &&
Object.entries({ Object.entries({
...childWidgets, ...childWidgets,
// ...(resizingComponentId &&
// childWidgets[resizingComponentId] && { resizingComponentId: childWidgets[resizingComponentId] }),
}).map(([key, box]) => { }).map(([key, box]) => {
const canShowInCurrentLayout = const canShowInCurrentLayout =
box.component.definition.others[currentLayout === 'mobile' ? 'showOnMobile' : 'showOnDesktop'].value; box.component.definition.others[currentLayout === 'mobile' ? 'showOnMobile' : 'showOnDesktop'].value;
@ -685,13 +498,9 @@ export const SubContainer = ({
allComponents={allComponents} allComponents={allComponents}
{...box} {...box}
mode={mode} mode={mode}
// resizingStatusChanged={(status) => setIsResizing(status)}
// draggingStatusChanged={(status) => setIsDragging(status)}
inCanvas={true} inCanvas={true}
zoomLevel={zoomLevel} zoomLevel={zoomLevel}
// setSelectedComponent={setSelectedComponent}
selectedComponent={selectedComponent} selectedComponent={selectedComponent}
// deviceWindowWidth={deviceWindowWidth}
isSelectedComponent={ isSelectedComponent={
mode === 'edit' ? selectedComponents.find((component) => component.id === key) : false mode === 'edit' ? selectedComponents.find((component) => component.id === key) : false
} }
@ -703,37 +512,8 @@ export const SubContainer = ({
onComponentHover={onComponentHover} onComponentHover={onComponentHover}
hoveredComponent={hoveredComponent} hoveredComponent={hoveredComponent}
parentId={parent} parentId={parent}
// sideBarDebugger={sideBarDebugger}
isMultipleComponentsSelected={selectedComponents?.length > 1 ? true : false} isMultipleComponentsSelected={selectedComponents?.length > 1 ? true : false}
exposedVariables={exposedVariables ?? {}} 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} getContainerProps={getContainerProps}
/> />
</SubWidgetWrapper> </SubWidgetWrapper>
@ -758,7 +538,6 @@ export const SubContainer = ({
</center> </center>
</div> </div>
)} )}
{/* <GhostWidget layout={childWidgets[]} */}
</SubContianerWrapper> </SubContianerWrapper>
); );
}; };
@ -816,7 +595,7 @@ const SubWidgetWrapper = ({
useEffect(() => { useEffect(() => {
const controlBox = document.querySelector(`[target-id="${id}"]`); 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 //adding attribute instead of class since react-moveable seems to replace classes internally on scroll stop
if (!isOnScreen && isSelected && !isDragging && !isResizing) { if (!isOnScreen && isSelected && !isDragging && !isResizing) {
controlBox?.classList.add('hide-control'); controlBox?.classList.add('hide-control');
@ -855,7 +634,6 @@ const SubWidgetWrapper = ({
}; };
const SubContianerWrapper = ({ children, isDragging, isResizing, isGridActive, readOnly, drop, styles, parent }) => { const SubContianerWrapper = ({ children, isDragging, isResizing, isGridActive, readOnly, drop, styles, parent }) => {
// const [dragTarget] = useDragTarget();
return ( return (
<div <div
ref={drop} ref={drop}
@ -863,7 +641,6 @@ const SubContianerWrapper = ({ children, isDragging, isResizing, isGridActive, r
id={`canvas-${parent}`} id={`canvas-${parent}`}
data-parent={parent} data-parent={parent}
className={`sub-canvas real-canvas ${ className={`sub-canvas real-canvas ${
// (isDragging || isResizing || dragTarget === parent || isGridActive) && !readOnly ? 'show-grid' : 'hide-grid'
(isDragging || isResizing || 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); [x, y] = snapToGrid(canvasWidth, x, y);
console.log(`translate(${x}px, ${y}px)`);
const transform = `translate(${x}px, ${y}px)`; const transform = `translate(${x}px, ${y}px)`;
return { return {
transform, transform,

View file

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

View file

@ -37,6 +37,7 @@ import { useAppDataStore } from '@/_stores/appDataStore';
import { useEditorStore } from '@/_stores/editorStore'; import { useEditorStore } from '@/_stores/editorStore';
import { useGridStore } from '@/_stores/gridStore'; import { useGridStore } from '@/_stores/gridStore';
import { useResolveStore } from '@/_stores/resolverStore'; import { useResolveStore } from '@/_stores/resolverStore';
import { handleLowPriorityWork } from './editorHelpers';
const ERROR_TYPES = Object.freeze({ const ERROR_TYPES = Object.freeze({
ReferenceError: 'ReferenceError', ReferenceError: 'ReferenceError',
@ -110,41 +111,40 @@ export function onComponentOptionsChanged(component, options) {
export function onComponentOptionChanged(component, option_name, value) { export function onComponentOptionChanged(component, option_name, value) {
const componentName = component.name; 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 (isEditorReady) {
if (duplicateCurrentState !== null) { // Always update the current state if editor is ready
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 },
});
}
useCurrentStateStore.getState().actions.setCurrentState({ useCurrentStateStore.getState().actions.setCurrentState({
components: { ...components, [componentName]: componentData }, 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 (!_.isEmpty(useResolveStore.getState().lookupTable?.resolvedRefs) && path) {
if (option_name !== 'id') { const lookUpTable = useResolveStore.getState().lookupTable;
debouncedChange();
} else if (!componentData?.id) { const existingRef = lookUpTable.resolvedRefs?.get(lookUpTable.hints?.get(path));
debouncedChange();
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(); return Promise.resolve();
@ -1112,6 +1112,14 @@ export function runQuery(
}, },
errors: {}, errors: {},
}); });
useResolveStore.getState().actions.addAppSuggestions({
queries: {
[queryName]: {
data: [],
isLoading: true,
},
},
});
} }
let queryExecutionPromise = null; let queryExecutionPromise = null;
if (query.kind === 'runjs') { if (query.kind === 'runjs') {
@ -1288,9 +1296,15 @@ export function runQuery(
queries: { queries: {
[queryName]: { [queryName]: {
data: finalData, data: finalData,
isLoading: false,
}, },
}, },
}); });
const basePath = `queries.${queryName}`;
useResolveStore.getState().actions.updateLastUpdatedRefs([`${basePath}.data`, `${basePath}.isLoading`]);
resolve({ status: 'ok', data: finalData }); resolve({ status: 'ok', data: finalData });
onEvent(_self, 'onDataQuerySuccess', queryEvents, mode); onEvent(_self, 'onDataQuerySuccess', queryEvents, mode);
} }

View file

@ -178,3 +178,21 @@ export function handleLowPriorityWork(callback, timeout = null) {
const options = timeout ? { timeout } : {}; const options = timeout ? { timeout } : {};
window.requestIdleCallback(callback, options); 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++; renderCountRef.current++;
console.log(`CountingRender- Component ${componentName} rendered ${renderCountRef.current} times.`); console.log(`CountingRender- Component ${componentName} rendered ${renderCountRef.current} times.`);
// return renderCountRef.current; return renderCountRef.current;
} }
export default useRenderCount; export default useRenderCount;

View file

@ -1,6 +1,6 @@
import { shallow } from 'zustand/shallow'; import { shallow } from 'zustand/shallow';
import { create, zustandDevTools } from './utils'; import { create, zustandDevTools } from './utils';
import _, { omit } from 'lodash'; import _, { debounce, merge, omit } from 'lodash';
import { useResolveStore } from './resolverStore'; import { useResolveStore } from './resolverStore';
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-unresolved
import { diff } from 'deep-object-diff'; import { diff } from 'deep-object-diff';
@ -50,45 +50,7 @@ export const useCurrentStateStore = create(
...initialState, ...initialState,
actions: { actions: {
setCurrentState: (currentState) => { 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 }); 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) => { setErrors: (error) => {
set({ errors: { ...get().errors, ...error } }, false, { type: 'SET_ERRORS', 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 _ from 'lodash';
import { create } from './utils'; import { create } from './utils';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { useResolveStore } from './resolverStore';
const STORE_NAME = 'Editor'; const STORE_NAME = 'Editor';
export const EMPTY_ARRAY = []; export const EMPTY_ARRAY = [];
@ -36,7 +37,6 @@ const initialState = {
queryConfirmationList: [], queryConfirmationList: [],
currentPageId: null, currentPageId: null,
currentSessionId: uuid(), currentSessionId: uuid(),
currentStateDiff: [],
componentsNeedsUpdateOnNextRender: [], componentsNeedsUpdateOnNextRender: [],
}; };
@ -64,9 +64,18 @@ export const useEditorStore = create(
setIsEditorActive: (isEditorActive) => set(() => ({ isEditorActive })), setIsEditorActive: (isEditorActive) => set(() => ({ isEditorActive })),
updateEditorState: (state) => set((prev) => ({ ...prev, ...state })), updateEditorState: (state) => set((prev) => ({ ...prev, ...state })),
updateCurrentStateDiff: (currentStateDiff) => set(() => ({ currentStateDiff })), updateCurrentStateDiff: (currentStateDiff) => set(() => ({ currentStateDiff })),
updateComponentsNeedsUpdateOnNextRender: (componentsNeedsUpdateOnNextRender) => updateComponentsNeedsUpdateOnNextRender: (componentsNeedsUpdateOnNextRender) => {
set(() => ({ componentsNeedsUpdateOnNextRender })), set(() => ({ componentsNeedsUpdateOnNextRender }));
flushComponentsNeedsUpdateOnNextRender: () => 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 }), updateQueryConfirmationList: (queryConfirmationList) => set({ queryConfirmationList }),
setHoveredComponent: (hoveredComponent) => setHoveredComponent: (hoveredComponent) =>
@ -105,6 +114,9 @@ export const getComponentsToRenders = () => {
return useEditorStore.getState().componentsNeedsUpdateOnNextRender; return useEditorStore.getState().componentsNeedsUpdateOnNextRender;
}; };
export const flushComponentsToRender = () => { export const flushComponentsToRender = (componentIds = []) => {
useEditorStore.getState().actions.flushComponentsNeedsUpdateOnNextRender(); 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 { create, zustandDevTools } from './utils';
import { shallow } from 'zustand/shallow';
import { useDataQueriesStore } from '@/_stores/dataQueriesStore'; import { useDataQueriesStore } from '@/_stores/dataQueriesStore';
const queryManagerPreferences = JSON.parse(localStorage.getItem('queryManagerPreferences')) ?? {}; const queryManagerPreferences = JSON.parse(localStorage.getItem('queryManagerPreferences')) ?? {};

View file

@ -58,7 +58,7 @@ const initialState = {
hints: {}, hints: {},
resolvedRefs: {}, resolvedRefs: {},
}, },
lastUpdatedRefs: [],
referenceMapper: new ReferencesBiMap(), 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) => { addAppSuggestions: (partialRefState) => {
if (Object.keys(partialRefState).length === 0) return; if (Object.keys(partialRefState).length === 0) return;
@ -86,6 +96,8 @@ export const useResolveStore = create(
const lookupHintsMap = new Map([...get().lookupTable.hints]); const lookupHintsMap = new Map([...get().lookupTable.hints]);
const lookupResolvedRefs = new Map([...get().lookupTable.resolvedRefs]); const lookupResolvedRefs = new Map([...get().lookupTable.resolvedRefs]);
const newUpdatedrefs = [];
hintsMap.forEach((value, key) => { hintsMap.forEach((value, key) => {
const alreadyExists = lookupHintsMap.has(key); const alreadyExists = lookupHintsMap.has(key);
@ -97,6 +109,7 @@ export const useResolveStore = create(
resolvedRefs.delete(value); resolvedRefs.delete(value);
resolvedRefs.set(existingLookupId, newResolvedRef); resolvedRefs.set(existingLookupId, newResolvedRef);
newUpdatedrefs.push(key);
} }
}); });
@ -118,6 +131,7 @@ export const useResolveStore = create(
hints: lookupHintsMap, hints: lookupHintsMap,
resolvedRefs: lookupResolvedRefs, 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: () => { updateJSHints: () => {
const hints = createJavaScriptSuggestions(); const hints = createJavaScriptSuggestions();
set(() => ({ suggestions: { ...get().suggestions, jsHints: hints } })); set(() => ({ suggestions: { ...get().suggestions, jsHints: hints } }));

View file

@ -465,7 +465,12 @@ export function createReferencesLookup(refState, forQueryParams = false, initalL
} }
if (_type === 'Array') { if (_type === 'Array') {
map.set(newPath, { type: _type }); map.set(newPath, { type: _type });
buildMap(value, newPath);
if (path.startsWith('queries') && key === 'data' && value.length > 2) {
// do nothing
} else {
buildMap(value, newPath);
}
} else { } else {
map.set(newPath, { type: _type }); map.set(newPath, { type: _type });
} }

View file

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