(
{
+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]);