diff --git a/frontend/src/Editor/CodeEditor/SingleLineCodeEditor.jsx b/frontend/src/Editor/CodeEditor/SingleLineCodeEditor.jsx index 0b620851be..cb834b0498 100644 --- a/frontend/src/Editor/CodeEditor/SingleLineCodeEditor.jsx +++ b/frontend/src/Editor/CodeEditor/SingleLineCodeEditor.jsx @@ -130,7 +130,7 @@ const EditorInput = ({ if (totalReferences > 1) { const currentWord = queryInput.split('{{').pop().split('}}')[0]; - queryInput = currentWord; + queryInput = '{{' + currentWord + '}}'; } let completions = getAutocompletion(queryInput, validationType, hints, totalReferences); diff --git a/frontend/src/Editor/CodeEditor/autocompleteExtensionConfig.js b/frontend/src/Editor/CodeEditor/autocompleteExtensionConfig.js index ab08f79e82..a85238987c 100644 --- a/frontend/src/Editor/CodeEditor/autocompleteExtensionConfig.js +++ b/frontend/src/Editor/CodeEditor/autocompleteExtensionConfig.js @@ -67,7 +67,7 @@ export const generateHints = (hints, totalReferences = 1) => { if (!hints) return []; const suggestions = hints.map(({ hint, type }) => { - let displayedHint = type === 'js_method' ? `${hint}()` : hint; + let displayedHint = type === 'js_method' || type === 'Function' ? `${hint}()` : hint; const maxHintLength = 20; const hintLength = displayedHint.length; diff --git a/frontend/src/Editor/Components/TextInput.jsx b/frontend/src/Editor/Components/TextInput.jsx index 6084aa16d9..fca4800ec7 100644 --- a/frontend/src/Editor/Components/TextInput.jsx +++ b/frontend/src/Editor/Components/TextInput.jsx @@ -224,7 +224,7 @@ export const TextInput = function TextInput({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [disable]); - const renderInput = () => ( + return ( <>
); - - return <>{renderInput()}; }; diff --git a/frontend/src/Editor/Container.jsx b/frontend/src/Editor/Container.jsx index d2d742209c..98a2cf6382 100644 --- a/frontend/src/Editor/Container.jsx +++ b/frontend/src/Editor/Container.jsx @@ -13,7 +13,6 @@ import config from 'config'; import Spinner from '@/_ui/Spinner'; import { useHotkeys } from 'react-hotkeys-hook'; import { addComponents, addNewWidgetToTheEditor, isPDFSupported } from '@/_helpers/appUtils'; -import { useCurrentState } from '@/_stores/currentStateStore'; import { useAppVersionStore } from '@/_stores/appVersionStore'; import { useEditorStore } from '@/_stores/editorStore'; import { useAppInfo } from '@/_stores/appDataStore'; @@ -31,7 +30,7 @@ import { useDraggedSubContainer, useGridStore } from '@/_stores/gridStore'; const deviceWindowWidth = EditorConstants.deviceWindowWidth; export const Container = ({ - canvasWidth, + widthOfCanvas, mode, snapToGrid, onComponentClick, @@ -72,10 +71,13 @@ export const Container = ({ shallow ); + const canvasWidth = widthOfCanvas + ? widthOfCanvas + : document.getElementsByClassName('canvas-area')[0]?.getBoundingClientRect()?.width; const gridWidth = canvasWidth / noOfGrids; + const { appId } = useAppInfo(); - const currentState = useCurrentState(); const { appVersionsId, isVersionReleased } = useAppVersionStore( (state) => ({ appVersionsId: state?.editingVersion?.id, @@ -189,7 +191,7 @@ export const Container = ({ } else { const diffState = diff(components, boxes); - if (!_.isEmpty(diffState) && !isOnlyLayoutUpdate(diffState)) { + if (!_.isEmpty(diffState)) { setBoxes(components); } } @@ -244,6 +246,8 @@ export const Container = ({ return; } + if (!appDefinition.pages[currentPageId]?.components) return; + const newDefinition = { ...appDefinition, pages: { @@ -251,7 +255,7 @@ export const Container = ({ [currentPageId]: { ...appDefinition.pages[currentPageId], components: { - ...appDefinition.pages[currentPageId].components, + ...appDefinition.pages[currentPageId]?.components, ...boxes, }, }, @@ -594,23 +598,21 @@ export const Container = ({ ...updatedBoxes, }; - handleLowPriorityWork(() => { - const diffState = diff(boxes, newBoxes); + const diffState = diff(boxes, newBoxes); - setBoxes((prev) => { - const updatedComponentsAsperDiff = Object.keys(diffState).reduce((acc, key) => { - const component = newBoxes[key]; - if (component) { - acc[key] = component; - } - return acc; - }, {}); + setBoxes((prev) => { + const updatedComponentsAsperDiff = Object.keys(diffState).reduce((acc, key) => { + const component = newBoxes[key]; + if (component) { + acc[key] = component; + } + return acc; + }, {}); - return { - ...prev, - ...updatedComponentsAsperDiff, - }; - }); + return { + ...prev, + ...updatedComponentsAsperDiff, + }; }); updateCanvasHeight(newBoxes); @@ -762,7 +764,6 @@ export const Container = ({ onEvent, appDefinition, appDefinitionChanged, - currentState, appLoading, zoomLevel, setSelectedComponent, diff --git a/frontend/src/Editor/Editor.jsx b/frontend/src/Editor/Editor.jsx index 54c2e5f937..57c465e8a2 100644 --- a/frontend/src/Editor/Editor.jsx +++ b/frontend/src/Editor/Editor.jsx @@ -59,7 +59,7 @@ import { useDataSourcesStore } from '@/_stores/dataSourcesStore'; import { useDataQueriesStore } from '@/_stores/dataQueriesStore'; import { useAppVersionStore, useAppVersionActions } from '@/_stores/appVersionStore'; import { useQueryPanelStore } from '@/_stores/queryPanelStore'; -import { useCurrentStateStore, useCurrentState, getCurrentState } from '@/_stores/currentStateStore'; +import { useCurrentStateStore, getCurrentState } from '@/_stores/currentStateStore'; import { computeAppDiff, computeComponentPropertyDiff, @@ -184,8 +184,6 @@ const EditorComponent = (props) => { shallow ); - const currentState = useCurrentState(); - const [zoomLevel, setZoomLevel] = useState(1); const [isQueryPaneDragging, setIsQueryPaneDragging] = useState(false); const [isQueryPaneExpanded, setIsQueryPaneExpanded] = useState(false); //!check where this is used @@ -241,7 +239,7 @@ const EditorComponent = (props) => { }); useCurrentStateStore.getState().actions.setCurrentState({ globals: { - ...currentState.globals, + ...getCurrentState().globals, theme: { name: props?.darkMode ? 'dark' : 'light' }, urlparams: JSON.parse(JSON.stringify(queryString.parse(props.location.search))), currentUser: userVars, @@ -621,7 +619,7 @@ const EditorComponent = (props) => { const changeDarkMode = (newMode) => { useCurrentStateStore.getState().actions.setCurrentState({ globals: { - ...currentState.globals, + ...getCurrentState().globals, theme: { name: newMode ? 'dark' : 'light' }, }, }); @@ -1288,7 +1286,9 @@ const EditorComponent = (props) => { const _appDefinition = JSON.parse(JSON.stringify(appDefinition)); let newComponents = _appDefinition?.pages[currentPageId].components; const selectedComponents = useEditorStore.getState()?.selectedComponents; + const componentsIds = []; for (const selectedComponent of selectedComponents) { + componentsIds.push(selectedComponent.id); let top = newComponents[selectedComponent.id].layouts[currentLayout].top; let left = newComponents[selectedComponent.id].layouts[currentLayout].left; const width = newComponents[selectedComponent.id]?.layouts[currentLayout]?.width; @@ -1325,6 +1325,8 @@ const EditorComponent = (props) => { _appDefinition.pages[currentPageId].components = newComponents; appDefinitionChanged(_appDefinition, { containerChanges: true, widgetMovedWithKeyboard: true }); + // console.log('arpit::', { componentsIds }); + // updateComponentsNeedsUpdateOnNextRender(componentsIds); }; const copyComponents = () => @@ -1612,7 +1614,7 @@ const EditorComponent = (props) => { }; const globals = { - ...currentState.globals, + ...getCurrentState().globals, }; useCurrentStateStore.getState().actions.setCurrentState({ globals, page }); }; @@ -1654,7 +1656,7 @@ const EditorComponent = (props) => { const queryParamsString = queryParams.map(([key, value]) => `${key}=${value}`).join('&'); const globals = { - ...currentState.globals, + ...getCurrentState().globals, urlparams: JSON.parse(JSON.stringify(queryString.parse(queryParamsString))), }; @@ -2092,7 +2094,7 @@ const EditorComponent = (props) => { {defaultComponentStateComputed && ( <> { + const appDefData = useEditorStore.getState().appDefinition; + const appJson = JSON.parse(JSON.stringify(appDefData)); + const currentPageId = pageId ?? this.state.currentPageId; + const currentComponents = appJson.pages[currentPageId].components; + let dataQueries = JSON.parse(JSON.stringify(useDataQueriesStore.getState().dataQueries)); + let allEvents = JSON.parse(JSON.stringify(useAppDataStore.getState().events)); + + const entityReferencesInComponentDefinitions = findAllEntityReferences(currentComponents, [])?.filter( + (entity) => entity && isValidUUID(entity) + ); + + const entityReferencesInQueryOptions = findAllEntityReferences(dataQueries, [])?.filter( + (entity) => entity && isValidUUID(entity) + ); + + const entityReferencesInEvents = findAllEntityReferences(allEvents, [])?.filter( + (entity) => entity && isValidUUID(entity) + ); + + const manager = useResolveStore.getState().referenceMapper; + + if (Array.isArray(entityReferencesInComponentDefinitions) && entityReferencesInComponentDefinitions?.length > 0) { + let newComponentDefinition = JSON.parse(JSON.stringify(currentComponents)); + + entityReferencesInComponentDefinitions.forEach((entity) => { + const entityrefExists = manager.has(entity); + + if (entityrefExists) { + const value = manager.get(entity); + + newComponentDefinition = dfs(newComponentDefinition, entity, value); + } + }); + + const newAppDefinition = { + ...appJson, + pages: { + ...appJson.pages, + [currentPageId]: { + ...appJson.pages[currentPageId], + components: newComponentDefinition, + }, + }, + }; + + useEditorStore.getState().actions.updateEditorState({ + isUpdatingEditorStateInProcess: false, + appDefinition: newAppDefinition, + }); + + this.setState({ + appDefinition: newAppDefinition, + }); + } + + if (Array.isArray(entityReferencesInQueryOptions) && entityReferencesInQueryOptions?.length > 0) { + let newQueryOptions = {}; + dataQueries?.forEach((query) => { + newQueryOptions[query.id] = query.options; + ``; + }); + + entityReferencesInQueryOptions.forEach((entity) => { + const entityrefExists = manager.has(entity); + + if (entityrefExists) { + const value = manager.get(entity); + newQueryOptions = dfs(newQueryOptions, entity, value); + } + }); + + dataQueries = dataQueries.map((query) => { + const queryId = query.id; + const dqOptions = newQueryOptions[queryId]; + + return { + ...query, + options: dqOptions, + }; + }); + + useDataQueriesStore.getState().actions.setDataQueries(dataQueries, 'mappingUpdate'); + } + + if (Array.isArray(entityReferencesInEvents) && entityReferencesInEvents?.length > 0) { + let newEvents = JSON.parse(JSON.stringify(allEvents)); + + entityReferencesInEvents.forEach((entity) => { + const entityrefExists = manager.has(entity); + + if (entityrefExists) { + const value = manager.get(entity); + newEvents = dfs(newEvents, entity, value); + } + }); + + this.props.updateState({ + events: newEvents, + }); + } + + computeComponentState(currentComponents).then(async () => { + this.setState({ initialComputationOfStateDone: true, defaultComponentStateComputed: true }); + useCurrentStateStore.getState().actions.setEditorReady(true); + + if (loadType === 'appload') { + this.runQueries(dataQueries); + } + + const currentPageEvents = this.state.events.filter( + (event) => event.target === 'page' && event.sourceId === this.state.currentPageId + ); + + await this.handleEvent('onPageLoad', currentPageEvents); }); }; @@ -198,7 +314,7 @@ class ViewerComponent extends React.Component { }); useEditorStore.getState().actions.toggleCurrentLayout(this.props?.currentLayout == 'mobile' ? 'mobile' : 'desktop'); this.props.updateState({ events: data.events ?? [] }); - const currentPageComponents = appDefData?.pages[currentPageId]?.components; + const currentPageComponents = appDefData?.pages[currentPage.id]?.components; if (currentPageComponents && !_.isEmpty(currentPageComponents)) { const referenceManager = useResolveStore.getState().referenceMapper; @@ -234,110 +350,7 @@ class ViewerComponent extends React.Component { events: data.events ?? [], }, () => { - // const components = appDefData?.pages[currentPageId]?.components || {}; - - const appJson = JSON.parse(JSON.stringify(appDefData)); - const currentPageId = useEditorStore.getState().currentPageId; - const currentComponents = useEditorStore.getState().appDefinition?.pages?.[currentPageId]?.components; - let dataQueries = JSON.parse(JSON.stringify(useDataQueriesStore.getState().dataQueries)); - let allEvents = JSON.parse(JSON.stringify(useAppDataStore.getState().events)); - - const entityReferencesInComponentDefinitions = findAllEntityReferences(currentComponents, [])?.filter( - (entity) => entity && isValidUUID(entity) - ); - - const entityReferencesInQueryOptions = findAllEntityReferences(dataQueries, [])?.filter( - (entity) => entity && isValidUUID(entity) - ); - - const entityReferencesInEvents = findAllEntityReferences(allEvents, [])?.filter( - (entity) => entity && isValidUUID(entity) - ); - - const manager = useResolveStore.getState().referenceMapper; - - if ( - Array.isArray(entityReferencesInComponentDefinitions) && - entityReferencesInComponentDefinitions?.length > 0 - ) { - let newComponentDefinition = JSON.parse(JSON.stringify(currentComponents)); - - entityReferencesInComponentDefinitions.forEach((entity) => { - const entityrefExists = manager.has(entity); - - if (entityrefExists) { - const value = manager.get(entity); - newComponentDefinition = dfs(newComponentDefinition, entity, value); - } - }); - - const newAppDefinition = produce(appJson, (draft) => { - draft.pages[homePageId].components = newComponentDefinition; - }); - - useEditorStore.getState().actions.updateEditorState({ - isUpdatingEditorStateInProcess: false, - appDefinition: newAppDefinition, - }); - } - - if (Array.isArray(entityReferencesInQueryOptions) && entityReferencesInQueryOptions?.length > 0) { - let newQueryOptions = {}; - dataQueries?.forEach((query) => { - newQueryOptions[query.id] = query.options; - ``; - }); - - entityReferencesInQueryOptions.forEach((entity) => { - const entityrefExists = manager.has(entity); - - if (entityrefExists) { - const value = manager.get(entity); - newQueryOptions = dfs(newQueryOptions, entity, value); - } - }); - - dataQueries = dataQueries.map((query) => { - const queryId = query.id; - const dqOptions = newQueryOptions[queryId]; - - return { - ...query, - options: dqOptions, - }; - }); - - useDataQueriesStore.getState().actions.setDataQueries(dataQueries, 'mappingUpdate'); - } - - if (Array.isArray(entityReferencesInEvents) && entityReferencesInEvents?.length > 0) { - let newEvents = JSON.parse(JSON.stringify(allEvents)); - - entityReferencesInEvents.forEach((entity) => { - const entityrefExists = manager.has(entity); - - if (entityrefExists) { - const value = manager.get(entity); - newEvents = dfs(newEvents, entity, value); - } - }); - - this.props.updateState({ - events: newEvents, - }); - } - - computeComponentState(currentComponents).then(async () => { - this.setState({ initialComputationOfStateDone: true, defaultComponentStateComputed: true }); - useCurrentStateStore.getState().actions.setEditorReady(true); - this.runQueries(dataQueries); - - const currentPageEvents = this.state.events.filter( - (event) => event.target === 'page' && event.sourceId === this.state.currentPageId - ); - - await this.handleEvent('onPageLoad', currentPageEvents); - }); + this.onViewerLoadUpdateEntityReferences(currentPage.id, 'appload'); } ); }; @@ -637,6 +650,8 @@ class ViewerComponent extends React.Component { const defaultParams = getPreviewQueryParams(); if (this.state.currentPageId === id) return; + useCurrentStateStore.getState().actions.setEditorReady(false); + useResolveStore.getState().actions.resetStore(); const { handle } = this.state.appDefinition.pages[id]; @@ -654,20 +669,58 @@ class ViewerComponent extends React.Component { ? `version=${navigationParams.version}` : ''; - this.props.navigate( - `/applications/${this.state.slug}/${handle}?${!_.isEmpty(defaultParams) ? navigationParamsString : ''}${ - queryParamsString ? `${!_.isEmpty(defaultParams) ? '&' : ''}${queryParamsString}` : '' - }`, - { - state: { - isSwitchingPage: true, - }, + useEditorStore.getState().actions.updateEditorState({ + currentPageId: id, + }); + + const currentPageComponents = this.state.appDefinition?.pages[id]?.components; + + if (currentPageComponents && !_.isEmpty(currentPageComponents)) { + const referenceManager = useResolveStore.getState().referenceMapper; + + const newComponents = Object.keys(currentPageComponents).map((componentId) => { + const component = currentPageComponents[componentId]; + + if (!referenceManager.get(componentId)) { + return { + id: componentId, + name: component.component.name, + }; + } + }); + + try { + useResolveStore.getState().actions.addEntitiesToMap(newComponents); + } catch (error) { + console.error(error); } - ); + } + + const toNavigate = `/applications/${this.state.slug}/${handle}?${ + !_.isEmpty(defaultParams) ? navigationParamsString : '' + }${queryParamsString ? `${!_.isEmpty(defaultParams) ? '&' : ''}${queryParamsString}` : ''}`; + + this.props.navigate(toNavigate, { + state: { + isSwitchingPage: true, + }, + }); + this.onViewerLoadUpdateEntityReferences(id, 'page-switch'); }; handleEvent = (eventName, events, options) => { - return onEvent(this.getViewerRef(), eventName, events, options, 'view'); + const latestEvents = useAppDataStore.getState().events; + + const filteredEvents = latestEvents.filter((event) => { + const foundEvent = events.find((e) => e.id === event.id); + return foundEvent && foundEvent.name === eventName; + }); + + try { + return onEvent(this.getViewerRef(), eventName, filteredEvents, options, 'view'); + } catch (error) { + console.error(error); + } }; computeCanvasMaxWidth = () => { @@ -890,11 +943,12 @@ class ViewerComponent extends React.Component { } const withStore = (Component) => (props) => { const currentState = useCurrentStateStore(); - const { currentLayout, queryConfirmationList, currentPageId } = useEditorStore( + const { currentLayout, queryConfirmationList, currentPageId, appDefinition } = useEditorStore( (state) => ({ currentLayout: state?.currentLayout, queryConfirmationList: state?.queryConfirmationList, currentPageId: state?.currentPageId, + appDefinition: state?.appDefinition, }), shallow ); @@ -920,13 +974,12 @@ const withStore = (Component) => (props) => { await new Promise((resolve) => setTimeout(resolve, 0)); } - // Flush only updated components flushComponentsToRender(updatedComponentIds); } React.useEffect(() => { if (lastUpdatedRef.length > 0) { - const currentComponents = useEditorStore.getState().appDefinition?.pages?.[currentPageId]?.components || {}; + const currentComponents = appDefinition?.pages?.[currentPageId]?.components || {}; const componentIdsWithReferences = findComponentsWithReferences(currentComponents, lastUpdatedRef); if (componentIdsWithReferences.length > 0) { diff --git a/frontend/src/_stores/editorStore.js b/frontend/src/_stores/editorStore.js index cc540c6992..ce550ed609 100644 --- a/frontend/src/_stores/editorStore.js +++ b/frontend/src/_stores/editorStore.js @@ -118,5 +118,5 @@ export const flushComponentsToRender = (componentIds = []) => { if (!componentIds.length) return; useEditorStore.getState().actions.flushComponentsNeedsUpdateOnNextRender(componentIds); - useResolveStore.getState().actions.getLastUpdatedRefs(); + useResolveStore.getState().actions.flushLastUpdatedRefs(); };