diff --git a/frontend/ee b/frontend/ee index dbb130bfd8..e95965cf14 160000 --- a/frontend/ee +++ b/frontend/ee @@ -1 +1 @@ -Subproject commit dbb130bfd859ab795557a36dc26936aa2252e248 +Subproject commit e95965cf14966d3f5727835adf5b8d3ca55a569e diff --git a/frontend/src/AppBuilder/AppBuilder.jsx b/frontend/src/AppBuilder/AppBuilder.jsx index b300329eef..ab117b2a95 100644 --- a/frontend/src/AppBuilder/AppBuilder.jsx +++ b/frontend/src/AppBuilder/AppBuilder.jsx @@ -1,4 +1,4 @@ -import React, { Suspense, lazy, useEffect } from 'react'; +import React, { Suspense } from 'react'; import useStore from '@/AppBuilder/_stores/store'; import useAppData from '@/AppBuilder/_hooks/useAppData'; import { TJLoader } from '@/_ui/TJLoader/TJLoader'; @@ -28,7 +28,6 @@ import ArtifactPreview from './ArtifactPreview'; // TODO: split Loader into separate component and remove editor loading state from Editor export const Editor = ({ id: appId, darkMode, moduleId = 'canvas', switchDarkMode, appType = 'front-end' }) => { useAppData(appId, moduleId, darkMode); - const isRightSidebarOpen = useStore((state) => state.isRightSidebarOpen); const isEditorLoading = useStore((state) => state.loaderStore.modules[moduleId].isEditorLoading, shallow); const currentMode = useStore((state) => state.modeStore.modules[moduleId].currentMode, shallow); const isModuleEditor = appType === 'module'; @@ -64,7 +63,6 @@ export const Editor = ({ id: appId, darkMode, moduleId = 'canvas', switchDarkMod isUserInZeroToOneFlow={isUserInZeroToOneFlow} /> - {isUserInZeroToOneFlow ? ( ) : ( @@ -74,7 +72,7 @@ export const Editor = ({ id: appId, darkMode, moduleId = 'canvas', switchDarkMod - {isRightSidebarOpen && }{' '} + diff --git a/frontend/src/AppBuilder/AppCanvas/AppCanvas.jsx b/frontend/src/AppBuilder/AppCanvas/AppCanvas.jsx index 2cd94143c7..f5334b25ac 100644 --- a/frontend/src/AppBuilder/AppCanvas/AppCanvas.jsx +++ b/frontend/src/AppBuilder/AppCanvas/AppCanvas.jsx @@ -16,7 +16,6 @@ import { RIGHT_SIDEBAR_WIDTH, } from './appCanvasConstants'; import cx from 'classnames'; -import FreezeVersionInfo from '@/AppBuilder/Header/FreezeVersionInfo'; import { computeCanvasContainerHeight } from '../_helpers/editorHelpers'; import AutoComputeMobileLayoutAlert from './AutoComputeMobileLayoutAlert'; import useAppDarkMode from '@/_hooks/useAppDarkMode'; @@ -25,18 +24,18 @@ import { DeleteWidgetConfirmation } from './DeleteWidgetConfirmation'; import useSidebarMargin from './useSidebarMargin'; import PagesSidebarNavigation from '../RightSideBar/PageSettingsTab/PageMenu/PagesSidebarNavigation'; import { resolveReferences } from '@/_helpers/utils'; -import useRightSidebarMargin from './userRightSidebarMargin'; import { DragGhostWidget } from './GhostWidgets'; import AppCanvasBanner from '../../AppBuilder/Header/AppCanvasBanner'; +import { debounce } from 'lodash'; -export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode }) => { +export const AppCanvas = ({ appId, switchDarkMode, darkMode }) => { const { moduleId, isModuleMode, appType } = useModuleContext(); const canvasContainerRef = useRef(); const handleCanvasContainerMouseUp = useStore((state) => state.handleCanvasContainerMouseUp, shallow); const canvasHeight = useStore((state) => state.appStore.modules[moduleId].canvasHeight); - const creationMode = useStore((state) => state.appStore.modules[moduleId].app.creationMode); const environmentLoadingState = useStore( - (state) => state.environmentLoadingState || state.loaderStore.modules[moduleId].isEditorLoading + (state) => state.environmentLoadingState || state.loaderStore.modules[moduleId].isEditorLoading, + shallow ); const [canvasWidth, setCanvasWidth] = useState(getCanvasWidth(moduleId)); const gridWidth = canvasWidth / NO_OF_GRIDS; @@ -46,18 +45,14 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode }) const queryPanelHeight = useStore((state) => state?.queryPanel?.queryPanelHeight || 0); const isDraggingQueryPane = useStore((state) => state.queryPanel.isDraggingQueryPane, shallow); const { isAppDarkMode } = useAppDarkMode(); - const canvasBgColor = useStore((state) => state.getCanvasBackgroundColor('canvas', isAppDarkMode), shallow); const canvasContainerHeight = computeCanvasContainerHeight(queryPanelHeight, isDraggingQueryPane); const isAutoMobileLayout = useStore((state) => state.getIsAutoMobileLayout(), shallow); const setIsComponentLayoutReady = useStore((state) => state.setIsComponentLayoutReady, shallow); const canvasMaxWidth = useAppCanvasMaxWidth({ mode: currentMode }); const editorMarginLeft = useSidebarMargin(canvasContainerRef); - // const editorMarginRight = useRightSidebarMargin(canvasContainerRef); - // const isPagesSidebarHidden = useStore((state) => state.getPagesSidebarVisibility('canvas'), shallow); - const isSidebarOpen = useStore((state) => state.isSidebarOpen, shallow); const getPageId = useStore((state) => state.getCurrentPageId, shallow); const isRightSidebarOpen = useStore((state) => state.isRightSidebarOpen, shallow); - const isRightSidebarPinned = useStore((state) => state.isRightSidebarPinned, shallow); + const isSidebarOpen = useStore((state) => state.isSidebarOpen, shallow); const currentPageId = useStore((state) => state.modules[moduleId].currentPageId); const homePageId = useStore((state) => state.appStore.modules[moduleId].app.homePageId); @@ -65,10 +60,9 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode }) localStorage.getItem('isPagesSidebarPinned') !== 'false' ); - const { globalSettings, pages, pageSettings, switchPage } = useStore( + const { globalSettings, pageSettings, switchPage } = useStore( (state) => ({ globalSettings: state.globalSettings, - pages: state.modules.canvas.pages, pageSettings: state.pageSettings, switchPage: state.switchPage, }), @@ -76,12 +70,10 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode }) ); const showHeader = !globalSettings?.hideHeader; - const { definition: { styles = {}, properties = {} } = {} } = pageSettings ?? {}; + const { definition: { properties = {} } = {} } = pageSettings ?? {}; const { position, disableMenu, showOnDesktop } = properties ?? {}; const isPagesSidebarHidden = resolveReferences(disableMenu?.value); - const hideSidebar = isModuleMode || isPagesSidebarHidden || appType === 'module'; - useEffect(() => { // Need to remove this if we shift setExposedVariable Logic outside of components // Currently present to run onLoadQueries after the component is mounted @@ -90,7 +82,7 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode }) }, []); useEffect(() => { - function handleResize() { + function handleResizeImmediate() { const _canvasWidth = moduleId === 'canvas' ? document.getElementById('real-canvas')?.getBoundingClientRect()?.width @@ -98,6 +90,8 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode }) if (_canvasWidth !== 0) setCanvasWidth(_canvasWidth); } + const handleResize = debounce(handleResizeImmediate, 300); + if (moduleId === 'canvas') { window.addEventListener('resize', handleResize); } else { @@ -108,15 +102,17 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode }) return () => { if (elem) resizeObserver.unobserve(elem); resizeObserver.disconnect(); + handleResize.cancel(); }; } - handleResize(); + handleResizeImmediate(); - return () => window.removeEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + handleResize.cancel(); + }; }, [currentLayout, canvasMaxWidth, isViewerSidebarPinned, moduleId, isRightSidebarOpen]); - useEffect(() => {}, [isViewerSidebarPinned]); - const canvasContainerStyles = useMemo(() => { const canvasBgColor = currentMode === 'view' @@ -211,7 +207,6 @@ export const AppCanvas = ({ appId, isViewer = false, switchDarkMode, darkMode }) ); }; - const sortedComponents = useSortedComponents(components, currentLayout, id); + const sortedComponents = useSortedComponents(components, currentLayout, id, moduleId); return (
))}
@@ -309,3 +310,7 @@ export const Container = React.memo( ); } ); + +Container.displayName = 'Container'; + +export { Container }; diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx index dbe9ed941d..addd47f6c6 100644 --- a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx +++ b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx @@ -871,7 +871,6 @@ export default function Grid({ gridWidth, currentLayout }) { if (getHoveredComponentForGrid() !== e.target.id) { return false; } - toggleRightSidebar(); newDragParentId.current = boxList.find((box) => box.id === e.target.id)?.parent; e?.moveable?.controlBox?.removeAttribute('data-off-screen'); @@ -983,6 +982,7 @@ export default function Grid({ gridWidth, currentLayout }) { useStore.getState().setDraggingComponentId(e.target.id); showGridLines(); isDraggingRef.current = true; + toggleRightSidebar(); } const currentWidget = boxList.find((box) => box.id === e.target.id); const currentParentId = diff --git a/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx b/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx index 0409d22d77..1d6189eee8 100644 --- a/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx +++ b/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx @@ -7,7 +7,6 @@ import { renderTooltip } from '@/_helpers/appUtils'; import { useTranslation } from 'react-i18next'; import ErrorBoundary from '@/_ui/ErrorBoundary'; import { BOX_PADDING } from './appCanvasConstants'; -import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext'; const SHOULD_ADD_BOX_SHADOW_AND_VISIBILITY = [ 'Table', @@ -48,13 +47,12 @@ const RenderWidget = ({ widgetWidth, inCanvas = false, darkMode, + moduleId, }) => { - const { moduleId } = useModuleContext(); - const componentDefinition = useStore((state) => state.getComponentDefinition(id, moduleId), shallow); + const component = useStore((state) => state.getComponentDefinition(id, moduleId)?.component, shallow); const getDefaultStyles = useStore((state) => state.debugger.getDefaultStyles, shallow); const adjustComponentPositions = useStore((state) => state.adjustComponentPositions, shallow); const componentCount = useStore((state) => state.getContainerChildrenMapping(id)?.length || 0, shallow); - const component = componentDefinition?.component; const componentName = component?.name; const [key, setKey] = useState(Math.random()); const resolvedProperties = useStore( @@ -74,7 +72,7 @@ const RenderWidget = ({ (state) => state.getResolvedComponent(id, subContainerIndex, moduleId)?.generalStyles, shallow ); - const unResolvedValidation = componentDefinition?.component?.definition?.validation || {}; + const unResolvedValidation = component?.definition?.validation || {}; // const others = useStore((state) => state.getResolvedComponent(id, subContainerIndex)?.others, shallow); const updateDependencyValues = useStore((state) => state.updateDependencyValues, shallow); const validateWidget = useStore((state) => state.validateWidget, shallow); @@ -153,7 +151,7 @@ const RenderWidget = ({ useEffect(() => { setExposedVariable('id', id); }, []); - if (!componentDefinition?.component) return null; + if (!component) return null; const disabledState = resolvedProperties?.disabledState; const loadingState = resolvedProperties?.loadingState; @@ -219,4 +217,7 @@ const RenderWidget = ({ ); }; + +RenderWidget.displayName = 'RenderWidget'; + export default memo(RenderWidget); diff --git a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx index 057781f8ec..2616691311 100644 --- a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx +++ b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx @@ -6,7 +6,6 @@ import { ConfigHandle } from './ConfigHandle/ConfigHandle'; import { useGridStore } from '@/_stores/gridStore'; import cx from 'classnames'; import RenderWidget from './RenderWidget'; -import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext'; import { NO_OF_GRIDS } from './appCanvasConstants'; const WidgetWrapper = memo( @@ -21,8 +20,8 @@ const WidgetWrapper = memo( readOnly, mode, darkMode, + moduleId, }) => { - const { moduleId } = useModuleContext(); const calculateMoveableBoxHeightWithId = useStore((state) => state.calculateMoveableBoxHeightWithId, shallow); const stylesDefinition = useStore( (state) => state.getComponentDefinition(id, moduleId)?.component?.definition?.styles, @@ -127,6 +126,7 @@ const WidgetWrapper = memo( onOptionChange={onOptionChange} darkMode={darkMode} onOptionsChange={onOptionsChange} + moduleId={moduleId} /> @@ -135,4 +135,6 @@ const WidgetWrapper = memo( } ); +WidgetWrapper.displayName = 'WidgetWrapper'; + export default WidgetWrapper; diff --git a/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx b/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx index 16b8a74f77..5b12ff0f9b 100644 --- a/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx +++ b/frontend/src/AppBuilder/RightSideBar/ComponentManagerTab/DragLayer.jsx @@ -37,8 +37,6 @@ export const DragLayer = ({ index, component, isModuleTab = false, disabled = fa toggleRightSidebar(!isRightSidebarOpen); } setShowModuleBorder(true); - } else { - setShowModuleBorder(false); } }, [isDragging, setShowModuleBorder, isModuleEditor, toggleRightSidebar]); diff --git a/frontend/src/AppBuilder/RightSideBar/PageSettingsTab/PageMenu/PagesSidebarNavigation.jsx b/frontend/src/AppBuilder/RightSideBar/PageSettingsTab/PageMenu/PagesSidebarNavigation.jsx index 072ca62774..5c8cab9fc1 100644 --- a/frontend/src/AppBuilder/RightSideBar/PageSettingsTab/PageMenu/PagesSidebarNavigation.jsx +++ b/frontend/src/AppBuilder/RightSideBar/PageSettingsTab/PageMenu/PagesSidebarNavigation.jsx @@ -21,7 +21,6 @@ import { Overlay, Popover } from 'react-bootstrap'; export const PagesSidebarNavigation = ({ isMobileDevice, - pages, currentPageId, switchPage, darkMode, @@ -42,6 +41,7 @@ export const PagesSidebarNavigation = ({ const appName = useStore((state) => state.appStore.modules[moduleId].app.appName); const isSidebarOpen = useStore((state) => state.isSidebarOpen); const isRightSidebarOpen = useStore((state) => state.isRightSidebarOpen, shallow); + const pages = useStore((state) => state.modules.canvas.pages, shallow); const navRef = useRef(null); const moreRef = useRef(null); diff --git a/frontend/src/AppBuilder/RightSideBar/RightSideBar.jsx b/frontend/src/AppBuilder/RightSideBar/RightSideBar.jsx index 414c3ea8b4..f38d478be7 100644 --- a/frontend/src/AppBuilder/RightSideBar/RightSideBar.jsx +++ b/frontend/src/AppBuilder/RightSideBar/RightSideBar.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import useStore from '@/AppBuilder/_stores/store'; import { ComponentConfigurationTab } from './ComponentConfigurationTab'; import ComponentsManagerTab from './ComponentManagerTab'; @@ -13,13 +13,8 @@ export const RightSideBar = ({ darkMode }) => { const activeTab = useStore((state) => state.activeRightSideBarTab); const isRightSidebarOpen = useStore((state) => state.isRightSidebarOpen); - const setRightSidebarOpen = useStore((state) => state.setRightSidebarOpen); - const isRightSidebarPinned = useStore((state) => state.isRightSidebarPinned); - const setActiveRightSideBarTab = useStore((state) => state.setActiveRightSideBarTab); const [popoverContentHeight, setPopoverContentHeight] = useState(queryPanelHeight); - const sidebarRef = useRef(null); - useEffect(() => { if (!isDraggingQueryPane) { setPopoverContentHeight( @@ -31,30 +26,10 @@ export const RightSideBar = ({ darkMode }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [queryPanelHeight, isDraggingQueryPane]); - // useEffect(() => { - // const rigthSidebarMenu = document.querySelector('.right-sidebar-toggle'); - // function handleClickOutside(event) { - // if ( - // sidebarRef.current && - // !sidebarRef.current.contains(event.target) && - // !rigthSidebarMenu.contains(event.target) && - // !isRightSidebarPinned - // ) { - // setRightSidebarOpen(false); - // setActiveRightSideBarTab(null); - // } - // } - - // document.addEventListener('mousedown', handleClickOutside); - // return () => { - // document.removeEventListener('mousedown', handleClickOutside); - // }; - // }, [isRightSidebarPinned, setActiveRightSideBarTab, setRightSidebarOpen]); - if (!isRightSidebarOpen) return null; return ( -
+
( { +const RenderGroup = ({ pageGroup, currentPage, darkMode, handlepageSwitch, currentPageId, icon }) => { const { moduleId } = useModuleContext(); const [isExpanded, setIsExpanded] = useState(true); const groupActive = currentPage.pageGroupId === pageGroup?.id; const homePageId = useStore((state) => state.appStore.modules[moduleId].app.homePageId); + const pages = useStore((state) => state.modules[moduleId].pages); const handleToggle = () => { setIsExpanded(!isExpanded); }; diff --git a/frontend/src/AppBuilder/Viewer/Viewer.jsx b/frontend/src/AppBuilder/Viewer/Viewer.jsx index 1e32d4eede..d528c003a1 100644 --- a/frontend/src/AppBuilder/Viewer/Viewer.jsx +++ b/frontend/src/AppBuilder/Viewer/Viewer.jsx @@ -17,7 +17,6 @@ import { ModuleProvider } from '@/AppBuilder/_contexts/ModuleContext'; import { getPatToken, setPatToken } from '@/AppBuilder/EmbedApp'; import Spinner from '@/_ui/Spinner'; import { checkIfLicenseNotValid } from '@/_helpers/appUtils'; -import toast from 'react-hot-toast'; import TooljetBanner from '../../Editor/Viewer/TooljetBanner'; export const Viewer = ({ @@ -43,7 +42,6 @@ export const Viewer = ({ currentCanvasWidth, currentPageId, globalSettings, - pages, pageSettings, updateCanvasHeight, appName, @@ -64,9 +62,6 @@ export const Viewer = ({ homePageId: state.appStore.modules[moduleId].app.homepageId, currentPageId: state.modules[moduleId].currentPageId, globalSettings: state.globalSettings, - pages: state.modules[moduleId].pages, - modules: state.modules, - globalSettingsChanged: state.globalSettingsChanged, pageSettings: state.pageSettings, updateCanvasHeight: state.updateCanvasBottomHeight, isMaintenanceOn: state.appStore.modules[moduleId].app.isMaintenanceOn, @@ -79,7 +74,6 @@ export const Viewer = ({ const getCurrentPageComponents = useStore((state) => state.getCurrentPageComponents(moduleId), shallow); const currentPageComponents = useMemo(() => getCurrentPageComponents, [getCurrentPageComponents]); - const changeDarkMode = useStore((state) => state.changeDarkMode); const isPagesSidebarHidden = useStore((state) => state.getPagesSidebarVisibility('canvas'), shallow); const canvasBgColor = useStore((state) => state.getCanvasBackgroundColor('canvas', darkMode), shallow); const deviceWindowWidth = window.screen.width - 5; @@ -106,7 +100,7 @@ export const Viewer = ({ }, [isSidebarPinned]); const { definition: { properties = {} } = {} } = pageSettings ?? {}; - const { position, hideHeader } = properties ?? {}; + const { position } = properties ?? {}; const canvasRef = useRef(null); const isMobilePreviewMode = selectedVersion?.id && currentLayout === 'mobile'; @@ -160,7 +154,6 @@ export const Viewer = ({ isAppLoaded={isAppLoaded} appName={appName} darkMode={darkMode} - pages={pages} currentPageId={currentPageId ?? homePageId} showViewerNavigation={!hideSidebar} handleAppEnvironmentChanged={handleAppEnvironmentChanged} @@ -176,7 +169,6 @@ export const Viewer = ({ showHeader={showHeader} appName={appName} darkMode={darkMode} - pages={pages} currentPageId={currentPageId ?? homePageId} showViewerNavigation={!hideSidebar} handleAppEnvironmentChanged={handleAppEnvironmentChanged} @@ -260,7 +252,6 @@ export const Viewer = ({ showHeader={showHeader && isAppLoaded} appName={appName} darkMode={darkMode} - pages={pages} currentPageId={currentPageId ?? homePageId} showViewerNavigation={!hideSidebar} handleAppEnvironmentChanged={handleAppEnvironmentChanged} diff --git a/frontend/src/AppBuilder/_hooks/useAppData.js b/frontend/src/AppBuilder/_hooks/useAppData.js index c98127e209..2260b9bf3b 100644 --- a/frontend/src/AppBuilder/_hooks/useAppData.js +++ b/frontend/src/AppBuilder/_hooks/useAppData.js @@ -5,21 +5,17 @@ import { appsService, appVersionService, dataqueryService, - datasourceService, orgEnvironmentConstantService, authenticationService, - orgEnvironmentVariableService, customStylesService, } from '@/_services'; import useStore from '@/AppBuilder/_stores/store'; -import { useEnvironmentsAndVersionsStore } from '@/_stores/environmentsAndVersionsStore'; -import { camelCase, cloneDeep, isEmpty, kebabCase, mapKeys, noop, rest } from 'lodash'; +import { camelCase, isEmpty, mapKeys, noop } from 'lodash'; import { usePrevious } from '@dnd-kit/utilities'; import { deepCamelCase } from '@/_helpers/appUtils'; import { useEventActions } from '../_stores/slices/eventsSlice'; import useRouter from '@/_hooks/use-router'; -import { extractEnvironmentConstantsFromConstantsList, navigate } from '../_utils/misc'; -import { getWorkspaceId } from '@/_helpers/utils'; +import { extractEnvironmentConstantsFromConstantsList } from '../_utils/misc'; import { shallow } from 'zustand/shallow'; import { fetchAndSetWindowTitle, pageTitles, retrieveWhiteLabelText } from '@white-label/whiteLabelling'; import { initEditorWalkThrough } from '@/AppBuilder/_helpers/createWalkThrough'; @@ -30,7 +26,6 @@ import { getPreviewQueryParams } from '@/_helpers/routes'; import { useLocation, useMatch, useParams } from 'react-router-dom'; import { useMounted } from '@/_hooks/use-mount'; import useThemeAccess from './useThemeAccess'; -import { handleError } from '@/_helpers/handleAppAccess'; import toast from 'react-hot-toast'; /** @@ -67,13 +62,13 @@ const useAppData = ( moduleMode = false ) => { const mounted = useMounted(); - const initModules = useStore((state) => state.initModules, shallow); + const initModules = useStore((state) => state.initModules); moduleMode && !mounted && initModules(moduleId); const { state } = useLocation(); const [currentSession, setCurrentSession] = useState(); + const setEditorLoading = useStore((state) => state.setEditorLoading); const setApp = useStore((state) => state.setApp); - const app = useStore((state) => state.appStore.modules[moduleId].app); const user = useStore((state) => state.user); const setCurrentVersionId = useStore((state) => state.setCurrentVersionId); const currentVersionId = useStore((state) => state.currentVersionId); @@ -90,10 +85,6 @@ const useAppData = ( const setPreviewData = useStore((state) => state.queryPanel.setPreviewData); // const fetchDataSources = useStore((state) => state.fetchDataSources); const fetchGlobalDataSources = useStore((state) => state.fetchGlobalDataSources); - const previousVersion = usePrevious(currentVersionId); - const events = useStore((state) => state.eventsSlice.module[moduleId]?.events || []); - const pages = useStore((state) => state.modules[moduleId]?.pages || []); - const currentPageId = useStore((state) => state.modules[moduleId].currentPageId); const setResolvedConstants = useStore((state) => state.setResolvedConstants); const setSecrets = useStore((state) => state.setSecrets); const setQueryMapping = useStore((state) => state.setQueryMapping); @@ -115,23 +106,17 @@ const useAppData = ( const cleanUpStore = useStore((state) => state.cleanUpStore); const selectedEnvironment = useStore((state) => state.selectedEnvironment); const setIsEditorFreezed = useStore((state) => state.setIsEditorFreezed); - const appMode = useStore((state) => state.globalSettings.appMode); - const selectedTheme = useStore((state) => state.globalSettings.theme); - const previousEnvironmentId = usePrevious(selectedEnvironment?.id); - const isComponentLayoutReady = useStore((state) => state.appStore.modules[moduleId].isComponentLayoutReady, shallow); - const pageSwitchInProgress = useStore((state) => state.pageSwitchInProgress); const setPageSwitchInProgress = useStore((state) => state.setPageSwitchInProgress); const selectedVersion = useStore((state) => state.selectedVersion); const setIsPublicAccess = useStore((state) => state.setIsPublicAccess); - const setModulesIsLoading = useStore((state) => state?.setModulesIsLoading ?? noop, shallow); - const setModulesList = useStore((state) => state?.setModulesList ?? noop, shallow); + const setModulesIsLoading = useStore((state) => state?.setModulesIsLoading ?? noop); + const setModulesList = useStore((state) => state?.setModulesList ?? noop); const setModuleDefinition = useStore((state) => state?.setModuleDefinition ?? noop); const getModuleDefinition = useStore((state) => state?.getModuleDefinition ?? noop); const deleteModuleDefinition = useStore((state) => state?.deleteModuleDefinition ?? noop); const themeAccess = useThemeAccess(); - const themeChanged = useStore((state) => state.themeChanged); const detectThemeChange = useStore((state) => state.detectThemeChange); const setConversation = useStore((state) => state.ai?.setConversation); const setDocsConversation = useStore((state) => state.ai?.setDocsConversation); @@ -142,10 +127,18 @@ const useAppData = ( const toggleLeftSidebar = useStore((state) => state.toggleLeftSidebar); const pathParams = useParams(); const slug = moduleMode ? '' : pathParams?.slug; + + const previousVersion = usePrevious(currentVersionId); + const events = useStore((state) => state.eventsSlice.module[moduleId]?.events || []); + const currentPageId = useStore((state) => state.modules[moduleId].currentPageId); + const appMode = useStore((state) => state.globalSettings.appMode); + const selectedTheme = useStore((state) => state.globalSettings.theme); + const previousEnvironmentId = usePrevious(selectedEnvironment?.id); + const isComponentLayoutReady = useStore((state) => state.appStore.modules[moduleId].isComponentLayoutReady); + const pageSwitchInProgress = useStore((state) => state.pageSwitchInProgress); const licenseStatus = useStore((state) => state.isLicenseValid()); - - - const match = useMatch('/applications/:slug/:pageHandle'); + const organizationId = useStore((state) => state.appStore.modules[moduleId].app.organizationId); + const appName = useStore((state) => state.appStore.modules[moduleId].app.name); const location = useRouter().location; @@ -542,10 +535,7 @@ const useAppData = ( useEffect(() => { if (isComponentLayoutReady) { runOnLoadQueries(moduleId).then(() => { - let startingPage = pages.find((page) => page.id === currentPageId); - const currentPageEvents = events.filter( - (event) => event.target === 'page' && event.sourceId === startingPage.id - ); + const currentPageEvents = events.filter((event) => event.target === 'page' && event.sourceId === currentPageId); handleEvent('onPageLoad', currentPageEvents, {}); }); } @@ -555,12 +545,12 @@ const useAppData = ( if (moduleId) return; fetchAndSetWindowTitle({ page: pageTitles.EDITOR, - appName: app.appName, + appName: appName, mode: mode, isReleased: isReleasedVersionId, licenseStatus: licenseStatus, }); - }, [app.appName, isReleasedVersionId, licenseStatus, mode, moduleId]); + }, [appName, isReleasedVersionId, licenseStatus, mode, moduleId]); useEffect(() => { const root = document.documentElement; @@ -655,7 +645,7 @@ const useAppData = ( } }); // fetchDataSources(currentVersionId, selectedEnvironment.id); - fetchGlobalDataSources(app.organizationId, currentVersionId, selectedEnvironment.id); + fetchGlobalDataSources(organizationId, currentVersionId, selectedEnvironment.id); setResolvedConstants(orgConstants); setSecrets(orgSecrets); } diff --git a/frontend/src/AppBuilder/_hooks/useSortedComponents.js b/frontend/src/AppBuilder/_hooks/useSortedComponents.js index 9877206444..f89328ead0 100644 --- a/frontend/src/AppBuilder/_hooks/useSortedComponents.js +++ b/frontend/src/AppBuilder/_hooks/useSortedComponents.js @@ -2,23 +2,43 @@ import { useMemo, useRef } from 'react'; import useStore from '@/AppBuilder/_stores/store'; import { shallow } from 'zustand/shallow'; -const useSortedComponents = (components, currentLayout, id) => { +const useSortedComponents = (components, currentLayout, id, moduleId) => { const getCurrentPageComponents = useStore((state) => state.getCurrentPageComponents, shallow); - const reorderContainerChildren = useStore((state) => state.reorderContainerChildren, shallow); + // Only subscribe to reorderContainerChildren when it's relevant to this specific container + const reorderContainerChildren = useStore((state) => { + const { containerId, triggerUpdate } = state.reorderContainerChildren; + // Only return an updated trigger when this specific container is being reordered + // Return a stable value for other containers to prevent unnecessary re-renders + if (containerId === id && moduleId === 'canvas') { + return { triggerUpdate, containerId, shouldReorder: true }; + } + return { triggerUpdate: 0, containerId: null, shouldReorder: false }; + }, shallow); + const prevForceUpdateRef = useRef(0); const prevComponentsOrder = useRef(components); // Function to sort the components based on position in container for tab navigation const sortedComponents = useMemo(() => { - const { triggerUpdate, containerId } = reorderContainerChildren; + const { triggerUpdate, shouldReorder } = reorderContainerChildren; - // If a forced update occurred for a different container, return the previous order + // Always recalculate if components array has changed (new component added/removed) + const componentsChanged = + prevComponentsOrder.current.length !== components.length || + !components.every((comp) => prevComponentsOrder.current.includes(comp)); + + // If a forced update occurred for this container, recalculate order const isForcedUpdate = prevForceUpdateRef.current !== triggerUpdate; if (isForcedUpdate) { prevForceUpdateRef.current = triggerUpdate; - if (containerId !== id) { - return prevComponentsOrder.current; - } + } + + // Skip recalculation only if: + // 1. This container is not the target of reorder + // 2. Components haven't changed + // 3. No forced update occurred + if (!shouldReorder && !componentsChanged && !isForcedUpdate) { + return prevComponentsOrder.current; } const currentPageComponents = getCurrentPageComponents(); @@ -41,7 +61,7 @@ const useSortedComponents = (components, currentLayout, id) => { prevComponentsOrder.current = newComponentsOrder; return newComponentsOrder; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [components, currentLayout, reorderContainerChildren.triggerUpdate, id]); + }, [components, currentLayout, reorderContainerChildren.triggerUpdate, reorderContainerChildren.shouldReorder]); return sortedComponents; }; diff --git a/frontend/src/AppBuilder/_stores/slices/rightSideBarSlice.js b/frontend/src/AppBuilder/_stores/slices/rightSideBarSlice.js index 027c29ca70..5831041dd8 100644 --- a/frontend/src/AppBuilder/_stores/slices/rightSideBarSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/rightSideBarSlice.js @@ -6,10 +6,12 @@ const initialState = { isRightSidebarPinned: false, }; -export const createRightSideBarSlice = (set) => ({ +export const createRightSideBarSlice = (set, get) => ({ ...initialState, setActiveRightSideBarTab: (tab) => set(() => ({ activeRightSideBarTab: tab }), false, 'setActiveRightSideBarTab'), - toggleRightSidebar: () => set((state) => ({ isRightSidebarOpen: !state.isRightSidebarOpen })), - setRightSidebarOpen: (open) => set(() => ({ isRightSidebarOpen: open })), - toggleRightSidebarPin: () => set((state) => ({ isRightSidebarPinned: !state.isRightSidebarPinned })), + toggleRightSidebar: () => + set((state) => ({ isRightSidebarOpen: !state.isRightSidebarOpen }), false, 'toggleRightSidebar'), + setRightSidebarOpen: (open) => set(() => ({ isRightSidebarOpen: open }), false, 'setRightSidebarOpen'), + toggleRightSidebarPin: () => + set((state) => ({ isRightSidebarPinned: !state.isRightSidebarPinned }), false, 'toggleRightSidebarPin'), }); diff --git a/frontend/src/_hooks/useRenderCount.jsx b/frontend/src/_hooks/useRenderCount.jsx index a56c42f985..26dfd9d8ec 100644 --- a/frontend/src/_hooks/useRenderCount.jsx +++ b/frontend/src/_hooks/useRenderCount.jsx @@ -1,12 +1,12 @@ import { useRef, useEffect } from 'react'; -function useRenderCount(componentName) { +function useRenderCount(componentName, options = {}) { const renderCountRef = useRef(0); renderCountRef.current++; useEffect(() => { - console.log(`${componentName} rendered: ${renderCountRef.current} times`); + console.log(`here--- ${componentName} rendered: ${renderCountRef.current} times `, options); // eslint-disable-next-line react-hooks/exhaustive-deps }, [renderCountRef.current, componentName]);