fixes: mutating of components from appDefinitions

This commit is contained in:
arpitnath 2023-08-05 19:18:58 +05:30
parent f1211ef595
commit ea0ab5b5c7
6 changed files with 88 additions and 70 deletions

View file

@ -351,7 +351,7 @@ export function CodeHinter({
height={'100%'}
onFocus={() => setFocused(true)}
onBlur={(editor, e) => {
e.stopPropagation();
e?.stopPropagation();
const value = editor.getValue()?.trimEnd();
onChange(value);
if (!isPreviewFocused.current) {

View file

@ -57,8 +57,9 @@ export const Container = ({
const components = useMemo(
() => appDefinition.pages[currentPageId]?.components ?? {},
// eslint-disable-next-line react-hooks/exhaustive-deps
[appDefinition.pages[currentPageId]]
[JSON.stringify(appDefinition)]
);
const currentState = useCurrentState();
const { appVersionsId, enableReleasedVersionPopupState, isVersionReleased } = useAppVersionStore(
(state) => ({
@ -180,7 +181,7 @@ export const Container = ({
},
};
appDefinitionChanged(newDefinition);
appDefinitionChanged(newDefinition, { containerChanges: true });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [boxes]);

View file

@ -2,7 +2,7 @@ import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { appService, authenticationService, appVersionService, orgEnvironmentVariableService } from '@/_services';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import _, { defaults, cloneDeep, isEqual, isEmpty, debounce, omit, update } from 'lodash';
import _, { defaults, cloneDeep, isEqual, isEmpty, debounce, omit, update, difference } from 'lodash';
import { Container } from './Container';
import { EditorKeyHooks } from './EditorKeyHooks';
import { CustomDragLayer } from './CustomDragLayer';
@ -53,6 +53,8 @@ import { shallow } from 'zustand/shallow';
import { useEditorActions, useEditorState, useEditorStore } from '@/_stores/editorStore';
import { useAppDataActions, useAppDataStore, useAppInfo } from '@/_stores/appDataStore';
import { useMounted } from '@/_hooks/use-mount';
// eslint-disable-next-line import/no-unresolved
import { diff } from 'deep-object-diff';
setAutoFreeze(false);
enablePatches();
@ -132,6 +134,8 @@ const EditorComponent = (props) => {
const selectionDragRef = useRef(null);
const selectionRef = useRef(null);
const prevAppDefinition = useRef(appDefinition);
useLayoutEffect(() => {
resetAllStores();
}, []);
@ -181,12 +185,12 @@ const EditorComponent = (props) => {
subscription.unsubscribe();
if (config.ENABLE_MULTIPLAYER_EDITING) props?.provider?.disconnect();
useEditorStore.getState().actions.setIsEditorActive(false);
prevAppDefinition.current = null;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// Ref to store the previous appDefinition for comparison
const prevAppDefinition = useRef(appDefinition);
useEffect(() => {
if (currentUser?.current_organization_id) {
@ -198,9 +202,17 @@ const EditorComponent = (props) => {
useEffect(() => {
const didAppDefinitionChanged = !_.isEqual(appDefinition, prevAppDefinition.current);
console.log('---arpit-- appDefinitionChanged', { dataQueries, didAppDefinitionChanged, appDefinition });
console.log('---arpit-- appDefinitionChanged [useEffect]', { didAppDefinitionChanged, isSaving });
if (didAppDefinitionChanged) {
console.log('---arpit-- updating [prevAppDefinition] [useEffect]', {
prev: prevAppDefinition.current,
curr: appDefinition,
});
prevAppDefinition.current = appDefinition;
}
if (mounted && didAppDefinitionChanged && currentPageId) {
console.log('---arpit-- appDefinitionChanged [mounted=true]', { appDefinition });
const components = appDefinition?.pages[currentPageId]?.components || {};
computeComponentState(components);
@ -209,7 +221,6 @@ const EditorComponent = (props) => {
autoSave();
}
}
prevAppDefinition.current = appDefinition;
}, [JSON.stringify({ appDefinition, currentPageId, dataQueries })]);
const editorRef = {
@ -298,7 +309,7 @@ const EditorComponent = (props) => {
};
const $componentDidMount = async () => {
console.log('---arpit-- componentDidMounted effect', { appDefinition, currentPageId });
// console.log('---arpit-- componentDidMounted effect', { appDefinition, currentPageId });
window.addEventListener('message', handleMessage);
// autoSave();
@ -612,13 +623,16 @@ const EditorComponent = (props) => {
await fetchDataSources(data.editing_version?.id);
await fetchDataQueries(data.editing_version?.id, true, true);
// let dataDefinition = defaults(data.definition, defaultDefinition(props.darkMode));
let dataDefinition = data.definition ?? defaults(data.definition, defaultDefinition(props.darkMode));
console.log('---arpit-- fetching app data', { startingPageHandle, data, dataDefinition });
const pages = Object.entries(dataDefinition.pages).map(([pageId, page]) => ({ id: pageId, ...page }));
const startingPageId = pages.filter((page) => page.handle === startingPageHandle)[0]?.id;
const homePageId = startingPageId || dataDefinition.homePageId;
const homePageId = !startingPageHandle || startingPageId === 'null' ? dataDefinition.homePageId : startingPageId;
console.log('---arpit-- fetching app data', {
data,
dataDefinition,
});
setCurrentPageId(homePageId);
@ -647,11 +661,6 @@ const EditorComponent = (props) => {
appDefinition: dataDefinition,
});
appDefinitionChanged(dataDefinition, {
skipAutoSave: true,
skipYmapUpdate: true,
});
for (const event of dataDefinition.pages[homePageId]?.events ?? []) {
await handleEvent(event.eventId, event);
}
@ -670,6 +679,7 @@ const EditorComponent = (props) => {
// !--------
const setAppDefinitionFromVersion = (version, shouldWeEditVersion = true) => {
console.log('---arpit [setAppFromVersion]--', version);
if (version?.id !== props.editingVersion?.id) {
appDefinitionChanged(defaults(version.definition, defaultDefinition(props.darkMode)), {
skipAutoSave: true,
@ -696,8 +706,11 @@ const EditorComponent = (props) => {
};
const appDefinitionChanged = (newDefinition, opts = {}) => {
console.log('--arpit | appDefinitionChanged func()');
if (_.isEqual(appDefinition, newDefinition)) return;
console.log('--arpit | appDefinitionChanged func() called', {
opts,
});
// if (_.isEqual(prevAppDefinition.current, newDefinition)) return;
if (config.ENABLE_MULTIPLAYER_EDITING && !opts.skipYmapUpdate) {
props.ymap?.set('appDef', {
newDefinition,
@ -711,40 +724,44 @@ const EditorComponent = (props) => {
return new Promise((resolve) => {
updateEditorState({
isSaving: true,
appDefinition: newDefinition,
// appDefinitionLocalVersion: uuid(),
});
// if (!opts.skipAutoSave) autoSave();
resolve();
});
}
// Create a new copy of appDefinition with lodash's cloneDeep
const updatedAppDefinition = _.cloneDeep(appDefinition);
if (_.isEmpty(updatedAppDefinition)) return;
const currentPageComponents = newDefinition.pages[currentPageId]?.components;
if (!updatedAppDefinition.pages[currentPageId]) {
updatedAppDefinition.pages[currentPageId] = {}; // Create a new object for the page if it doesn't exist
}
updatedAppDefinition.pages[currentPageId].components = currentPageComponents;
updatedAppDefinition.pages[currentPageId].components = currentPageComponents || {};
const diffPatches = diff(appDefinition, updatedAppDefinition);
// Call handleAddPatch with the list of changes (if needed)
handleAddPatch();
// Update the editor state with the new appDefinition
updateEditorState({
isSaving: true,
appDefinition: updatedAppDefinition,
// appDefinitionLocalVersion: uuid(),
console.log('--arpit | appDefinitionChanged func() | diffPatches', {
// appDefinition,
// updatedAppDefinition,
diffPatches,
});
if (!_.isEmpty(diffPatches)) {
updateEditorState({
isSaving: true,
appDefinition: updatedAppDefinition,
});
computeComponentState(updatedAppDefinition.pages[currentPageId]?.components);
} else {
toast.error('No changes in diff [appDefinitionChanged]');
}
// if (!opts.skipAutoSave) autoSave();
};
const saveEditingVersion = (isUserSwitchedVersion = false) => {
console.log('---arpit [saving - editionversion]--');
if (props.isVersionReleased && !isUserSwitchedVersion) {
updateEditorState({
isSaving: false,
@ -875,7 +892,6 @@ const EditorComponent = (props) => {
};
const componentDefinitionChanged = (componentDefinition, props) => {
console.log('---arpit [componentDefinitionChanged]', { props, componentDefinition });
if (props?.isVersionReleased) {
useAppVersionStore.getState().actions.enableReleasedVersionPopupState();
return;
@ -889,24 +905,31 @@ const EditorComponent = (props) => {
updatedAppDefinition.pages[currentPageId].components[componentDefinition.id].component =
componentDefinition.component;
// Call handleAddPatch with the list of changes (if needed)
handleAddPatch();
// Update the editor state with the new appDefinition
// // Update the editor state with the new appDefinition
updateEditorState({
isSaving: true,
appDefinition: updatedAppDefinition,
// appDefinitionLocalVersion: uuid()
});
// Other actions can be performed here if needed, like autoSave, ymap, etc.
computeComponentState(updatedAppDefinition.pages[currentPageId]?.components);
// autoSave();
props.ymap?.set('appDef', {
newDefinition: updatedAppDefinition,
editingVersionId: props.editingVersion?.id,
const diffPatches = diff(appDefinition, updatedAppDefinition);
console.log('---arpit [componentDefinitionChanged]', {
props,
diffPatches,
});
if (!isEmpty(diffPatches)) {
// handleAddPatch(diffPatches, diff(updatedAppDefinition, appDefinition));
appDefinitionChanged(updatedAppDefinition, { skipAutoSave: true, componentDefinitionChanged: true });
}
}
// // Other actions can be performed here if needed, like autoSave, ymap, etc.
// // computeComponentState(updatedAppDefinition.pages[currentPageId]?.components);
// // autoSave();
// // props.ymap?.set('appDef', {
// // newDefinition: updatedAppDefinition,
// // editingVersionId: props.editingVersion?.id,
// // });
// }
};
const removeComponent = (component) => {
@ -1168,10 +1191,6 @@ const EditorComponent = (props) => {
width: currentLayout === 'desktop' ? '100%' : '450px',
maxWidth:
+appDefinition.globalSettings.canvasMaxWidth + appDefinition.globalSettings.canvasMaxWidthType,
/**
* minWidth will be min(default canvas min width, user set max width). Done to avoid conflict between two
* default canvas min width = calc(((screen width - width component editor side bar) - width of editor sidebar on left) - width of left sidebar popover)
**/
backgroundColor: computeCanvasBackgroundColor(),
transform: 'translateZ(0)', //Hack to make modal position respect canvas container, else it positions w.r.t window.
@ -1278,7 +1297,6 @@ const EditorComponent = (props) => {
key={selectedComponents[0].id}
switchSidebarTab={switchSidebarTab}
darkMode={props.darkMode}
// appDefinitionLocalVersion={appDefinitionLocalVersion}
pages={getPagesWithIds()}
></Inspector>
) : (

View file

@ -99,9 +99,9 @@ export const Inspector = ({
return setInputFocus();
}
if (validateQueryName(newName)) {
let newComponent = { ...component };
let newComponent = JSON.parse(JSON.stringify(component));
newComponent.component.name = newName;
componentDefinitionChanged(newComponent);
componentDefinitionChanged(newComponent, { componentNameUpdated: true });
} else {
toast.error(
t(
@ -150,7 +150,7 @@ export const Inspector = ({
definition: newDefinition,
},
});
componentDefinitionChanged(newComponent);
componentDefinitionChanged(newComponent, { componentPropertyUpdated: true });
}
function layoutPropertyChanged(param, attr, value, paramType) {
@ -158,9 +158,7 @@ export const Inspector = ({
// User wants to show the widget on mobile devices
if (param.name === 'showOnMobile' && value === true) {
let newComponent = {
...component,
};
let newComponent = JSON.parse(JSON.stringify(component));
const { width, height } = newComponent.layouts['desktop'];
@ -174,7 +172,7 @@ export const Inspector = ({
},
};
componentDefinitionChanged(newComponent);
componentDefinitionChanged(newComponent, { layoutPropertyChanged: true });
// Child components should also have a mobile layout
const childComponents = Object.keys(allComponents).filter((key) => allComponents[key].parent === component.id);
@ -197,29 +195,29 @@ export const Inspector = ({
},
};
componentDefinitionChanged(newChild);
componentDefinitionChanged(newChild, { withChildLayout: true });
});
}
}
function eventUpdated(event, actionId) {
let newDefinition = { ...component.component.definition };
let newDefinition = JSON.parse(JSON.stringify(component.component.definition));
newDefinition.events[event.name] = { actionId };
let newComponent = {
...component,
};
componentDefinitionChanged(newComponent);
componentDefinitionChanged(newComponent, { eventUpdated: true });
}
function eventsChanged(newEvents, isReordered = false) {
let newDefinition;
if (isReordered) {
newDefinition = { ...component.component };
newDefinition = JSON.parse(JSON.stringify(component.component));
newDefinition.definition.events = newEvents;
} else {
newDefinition = { ...component.component.definition };
newDefinition = JSON.parse(JSON.stringify(component.component.definition));
newDefinition.events = newEvents;
}
@ -227,13 +225,13 @@ export const Inspector = ({
...component,
};
componentDefinitionChanged(newComponent);
componentDefinitionChanged(newComponent, { eventsChanged: true });
}
function eventOptionUpdated(event, option, value) {
console.log('eventOptionUpdated', event, option, value);
let newDefinition = { ...component.component.definition };
let newDefinition = JSON.parse(JSON.stringify(component.component.definition));
let eventDefinition = newDefinition.events[event.name] || { options: {} };
newDefinition.events[event.name] = { ...eventDefinition, options: { ...eventDefinition.options, [option]: value } };
@ -242,7 +240,7 @@ export const Inspector = ({
...component,
};
componentDefinitionChanged(newComponent);
componentDefinitionChanged(newComponent, { eventOptionUpdated: true });
}
const buildGeneralStyle = () => {

View file

@ -43,7 +43,8 @@ class ManageAppUsersComponent extends React.Component {
)
.catch((error) => {
this.setState({ isLoading: false });
toast.error(error);
const errorMessage = error?.message || 'Something went wrong';
toast.error(errorMessage);
});
};

View file

@ -1313,7 +1313,7 @@ const updateNewComponents = (pageId, appDefinition, newComponents, updateAppDefi
);
newAppDefinition.pages[pageId].components[newComponent.id] = newComponent;
});
updateAppDefinition(newAppDefinition);
updateAppDefinition(newAppDefinition, { addComponents: true });
};
export const cloneComponents = (