From 4b09509efb18afb4b6f5de78ed0e4b73dafe1e3d Mon Sep 17 00:00:00 2001
From: RAHEEL <mraheeliftikhar1994@gmail.com>
Date: Fri, 30 Aug 2024 22:16:56 +0500
Subject: [PATCH 1/5] update exports for adding innergrid in Kanban comp

---
 client/packages/lowcoder/src/index.sdk.ts | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/client/packages/lowcoder/src/index.sdk.ts b/client/packages/lowcoder/src/index.sdk.ts
index 1c4f68599..af3fda679 100644
--- a/client/packages/lowcoder/src/index.sdk.ts
+++ b/client/packages/lowcoder/src/index.sdk.ts
@@ -6,9 +6,13 @@ import * as styledNameExports from "styled-components";
 import styledDefault from "styled-components";
 export * as styledm from "styled-components";
 export * from "comps/comps/containerBase/containerCompBuilder";
+export * from "comps/comps/containerBase/iContainer";
+export * from "comps/comps/containerBase/utils";
+export * from "comps/comps/containerBase/simpleContainerComp";
 export * from "comps/utils/backgroundColorContext";
 export { getData } from "comps/comps/listViewComp/listViewUtils";
 export { gridItemCompToGridItems, InnerGrid } from "comps/comps/containerComp/containerView";
+export type { ContainerBaseProps } from "comps/comps/containerComp/containerView";
 
 export { Layers } from "constants/Layers";
 export * from "comps/controls/eventHandlerControl";
@@ -97,6 +101,7 @@ export * from "comps/controls/simpleStringControl";
 export * from "comps/controls/stringSimpleControl";
 export * from "comps/controls/styleControl";
 export * from "comps/controls/styleControlConstants";
+export * from "comps/controls/slotControl";
 
 // generators
 export * from "comps/generators/changeDataType";
@@ -114,6 +119,7 @@ export * from "comps/generators/withExposing";
 export * from "comps/generators/withIsLoading";
 export * from "comps/generators/withMethodExposing";
 export * from "comps/generators/withType";
+export * from "comps/generators/controlCompBuilder";
 
 export * from "appView/bootstrapAt";
 export * from "appView/LowcoderAppView";

From d91fe667aab0dfc053e888423f1eb4c8044c22c7 Mon Sep 17 00:00:00 2001
From: RAHEEL <mraheeliftikhar1994@gmail.com>
Date: Fri, 30 Aug 2024 22:18:37 +0500
Subject: [PATCH 2/5] memoize comps to minimize re-rendering

---
 .../src/comps/generators/uiCompBuilder.tsx    | 21 +++++++-------
 .../src/layout/compSelectionWrapper.tsx       |  4 +--
 .../packages/lowcoder/src/layout/gridItem.tsx | 28 +++++++++++--------
 .../lowcoder/src/layout/gridLayout.tsx        | 11 ++++----
 .../lowcoder/src/pages/common/help.tsx        |  4 ++-
 .../src/pages/common/previewHeader.tsx        |  5 +++-
 .../src/pages/editor/editorHotKeys.tsx        | 12 ++++----
 .../lowcoder/src/pages/editor/editorView.tsx  |  2 +-
 .../src/pages/editor/right/RightPanel.tsx     |  5 +++-
 .../src/pages/tutorials/editorTutorials.tsx   |  5 +++-
 10 files changed, 57 insertions(+), 40 deletions(-)

diff --git a/client/packages/lowcoder/src/comps/generators/uiCompBuilder.tsx b/client/packages/lowcoder/src/comps/generators/uiCompBuilder.tsx
index b4a5f5ea2..4e9b1d24c 100644
--- a/client/packages/lowcoder/src/comps/generators/uiCompBuilder.tsx
+++ b/client/packages/lowcoder/src/comps/generators/uiCompBuilder.tsx
@@ -44,10 +44,10 @@ export type NewChildren<ChildrenCompMap extends Record<string, Comp<unknown>>> =
     version: InstanceType<typeof StringControl>;
   };
 
-export function HidableView(props: {
+export const HidableView = React.memo((props: {
   children: JSX.Element | React.ReactNode;
   hidden: boolean;
-}) {
+}) => {
   const { readOnly } = useContext(ExternalEditorContext);
   if (readOnly) {
     return <>{props.children}</>;
@@ -64,15 +64,15 @@ export function HidableView(props: {
       </>
     );
   }
-}
+})
 
-export function ExtendedPropertyView<
+export const ExtendedPropertyView = React.memo(<
   ChildrenCompMap extends Record<string, Comp<unknown>>,
 >(props: {
   children: JSX.Element | React.ReactNode,
   childrenMap: NewChildren<ChildrenCompMap>
 }
-) {
+) => {
   const [compVersions, setCompVersions] = useState(['latest']);
   const [compName, setCompName] = useState('');
   const editorState = useContext(EditorContext);
@@ -129,7 +129,7 @@ export function ExtendedPropertyView<
       )}
     </>
   );
-}
+});
 
 export function uiChildren<
   ChildrenCompMap extends Record<string, Comp<unknown>>,
@@ -275,11 +275,11 @@ export const DisabledContext = React.createContext<boolean>(false);
 /**
  * Guaranteed to be in a react component, so that react hooks can be used internally
  */
-function UIView(props: {
+const UIView = React.memo((props: {
   innerRef: React.RefObject<HTMLDivElement>;
   comp: any;
   viewFn: any;
-}) {
+}) => {
   const comp = props.comp;
   const childrenProps = childrenToProps(comp.children);
   const childrenJsonProps = comp.toJsonValue();
@@ -397,8 +397,7 @@ function UIView(props: {
         width: '100%',
         height: '100%',
         margin: '0px',
-        padding:getPadding()
-          
+        padding: getPadding()
       }}
     >
       <HidableView hidden={childrenProps.hidden as boolean}>
@@ -406,4 +405,4 @@ function UIView(props: {
       </HidableView>
     </div>
   );
-}
+});
diff --git a/client/packages/lowcoder/src/layout/compSelectionWrapper.tsx b/client/packages/lowcoder/src/layout/compSelectionWrapper.tsx
index 447daa2a0..fd812a8b2 100644
--- a/client/packages/lowcoder/src/layout/compSelectionWrapper.tsx
+++ b/client/packages/lowcoder/src/layout/compSelectionWrapper.tsx
@@ -231,7 +231,7 @@ const HiddenIcon = styled(CloseEyeIcon)`
   }
 `;
 
-export const CompSelectionWrapper = (props: {
+export const CompSelectionWrapper = React.memo((props: {
   id?: string;
   compType: UICompType;
   className?: string;
@@ -376,4 +376,4 @@ export const CompSelectionWrapper = (props: {
       </SelectableDiv>
     </div>
   );
-};
+});
diff --git a/client/packages/lowcoder/src/layout/gridItem.tsx b/client/packages/lowcoder/src/layout/gridItem.tsx
index 47a04e87b..31893f15b 100644
--- a/client/packages/lowcoder/src/layout/gridItem.tsx
+++ b/client/packages/lowcoder/src/layout/gridItem.tsx
@@ -6,6 +6,7 @@ import React, {
   ReactElement,
   SyntheticEvent,
   useCallback,
+  useContext,
   useMemo,
   useRef,
   useState,
@@ -26,6 +27,7 @@ import {
   setTransform,
 } from "./utils";
 import styled from "styled-components";
+import { EditorContext } from "@lowcoder-ee/comps/editorState";
 
 type GridItemCallback<Data extends GridDragEvent | GridResizeEvent> = (
   i: string,
@@ -104,6 +106,7 @@ export function GridItem(props: GridItemProps) {
   const [resizing, setResizing] = useState<{ width: number; height: number } | undefined>();
   const [dragging, setDragging] = useState<{ top: number; left: number } | undefined>();
   const elementRef = useRef<HTMLDivElement>(null);
+  const editorState = useContext(EditorContext);
 
   // record the real height of the comp content
   const itemHeightRef = useRef<number | undefined>(undefined);
@@ -141,14 +144,17 @@ export function GridItem(props: GridItemProps) {
         onDrag={onDrag}
         onDragEnd={onDragEnd}
         onMouseDown={(e) => {
-          e.stopPropagation();
+          const parentContainer = editorState.findUIParentContainer(props.name!)?.toJsonValue();
 
           // allow mouseDown event on lowcoder-comp-kanban to make drag/drop work
-          if((props.compType as string).includes('lowcoder-comp-kanban')) return;
+          if(
+            (props.compType as string).includes('lowcoder-comp-kanban')
+            || parentContainer?.compType?.includes('lowcoder-comp-kanban')
+          ) return;
 
           // allow mouseDown event on lowcoder-comp-excalidraw to make drag/drop work
           if((props.compType as string).includes('lowcoder-comp-excalidraw')) return;
-
+          e.stopPropagation();
           const event = new MouseEvent("mousedown");
           document.dispatchEvent(event);
         }}
@@ -471,11 +477,11 @@ export function GridItem(props: GridItemProps) {
   return renderResult;
 }
 
-GridItem.defaultProps = {
-  className: "",
-  minH: 1,
-  minW: 1,
-  maxH: Infinity,
-  maxW: Infinity,
-  transformScale: 1,
-};
+// GridItem.defaultProps = {
+//   className: "",
+//   minH: 1,
+//   minW: 1,
+//   maxH: Infinity,
+//   maxW: Infinity,
+//   transformScale: 1,
+// };
diff --git a/client/packages/lowcoder/src/layout/gridLayout.tsx b/client/packages/lowcoder/src/layout/gridLayout.tsx
index 28e2e6220..77aaf965b 100644
--- a/client/packages/lowcoder/src/layout/gridLayout.tsx
+++ b/client/packages/lowcoder/src/layout/gridLayout.tsx
@@ -471,16 +471,16 @@ class GridLayout extends React.Component<GridLayoutProps, GridLayoutState> {
             isDraggable={isDraggable && isItemDraggable(item)}
             isResizable={isResizable && isItemResizable(item)}
             isSelectable={selectable}
-            transformScale={transformScale}
+            transformScale={transformScale || 1}
             w={item.w}
             h={extraItem?.hidden && !extraItem?.isSelected ? 0 : item.h}
             x={item.x}
             y={item.y}
             i={item.i}
-            minH={item.minH}
-            minW={item.minW}
-            maxH={item.maxH}
-            maxW={item.maxW}
+            minH={item.minH || 1}
+            minW={item.minW || 1}
+            maxH={item.maxH || Infinity}
+            maxW={item.maxW || Infinity}
             placeholder={item.placeholder}
             layoutHide={item.hide}
             static={item.static}
@@ -496,6 +496,7 @@ class GridLayout extends React.Component<GridLayoutProps, GridLayoutState> {
               bottom: (showName?.bottom ?? 0) + (this.ref.current?.scrollHeight ?? 0),
             }}
             zIndex={zIndex}
+            className=""
           >
             {child}
           </GridItem>
diff --git a/client/packages/lowcoder/src/pages/common/help.tsx b/client/packages/lowcoder/src/pages/common/help.tsx
index 2baaba225..64a99eca8 100644
--- a/client/packages/lowcoder/src/pages/common/help.tsx
+++ b/client/packages/lowcoder/src/pages/common/help.tsx
@@ -181,7 +181,7 @@ const introVideoUrl = trans("docUrls.introVideo");
 const issueUrl = trans("lowcoderUrl.createIssue");
 const discordUrl = trans("lowcoderUrl.discord");
 
-export function HelpDropdown(props: HelpDropdownProps) {
+function HelpDropdownComp(props: HelpDropdownProps) {
   const [showHelp, setShowHelp] = useState(true);
   const [version, setVersion] = useState("");
   const dispatch = useDispatch();
@@ -446,3 +446,5 @@ export function HelpDropdown(props: HelpDropdownProps) {
     </HelpWrapper>
   </>);
 }
+
+export const HelpDropdown = React.memo(HelpDropdownComp);
diff --git a/client/packages/lowcoder/src/pages/common/previewHeader.tsx b/client/packages/lowcoder/src/pages/common/previewHeader.tsx
index faaa28f53..10afb9817 100644
--- a/client/packages/lowcoder/src/pages/common/previewHeader.tsx
+++ b/client/packages/lowcoder/src/pages/common/previewHeader.tsx
@@ -20,6 +20,7 @@ import { getBrandingConfig } from "../../redux/selectors/configSelectors";
 import { HeaderStartDropdown } from "./headerStartDropdown";
 import { useParams } from "react-router";
 import { AppPathParams } from "constants/applicationConstants";
+import React from "react";
 
 const HeaderFont = styled.div<{ $bgColor: string }>`
   font-weight: 500;
@@ -127,7 +128,7 @@ export function HeaderProfile(props: { user: User }) {
   );
 }
 
-export const PreviewHeader = () => {
+const PreviewHeaderComp = () => {
   const params = useParams<AppPathParams>();
   const user = useSelector(getUser);
   const application = useSelector(currentApplication);
@@ -203,3 +204,5 @@ export const PreviewHeader = () => {
     />
   );
 };
+
+export const PreviewHeader = React.memo(PreviewHeaderComp);
diff --git a/client/packages/lowcoder/src/pages/editor/editorHotKeys.tsx b/client/packages/lowcoder/src/pages/editor/editorHotKeys.tsx
index 350baa2f7..ed99d4c73 100644
--- a/client/packages/lowcoder/src/pages/editor/editorHotKeys.tsx
+++ b/client/packages/lowcoder/src/pages/editor/editorHotKeys.tsx
@@ -113,7 +113,7 @@ function handleMouseDown(e: MouseEvent, editorState: EditorState, showLeftPanel:
   }
 }
 
-export function EditorGlobalHotKeys(props: GlobalProps) {
+export const EditorGlobalHotKeys = React.memo((props: GlobalProps) => {
   const editorState = useContext(EditorContext);
   const { history: editorHistory } = useContext(ExternalEditorContext);
   const { togglePanel, panelStatus, toggleShortcutList } = props;
@@ -155,7 +155,7 @@ export function EditorGlobalHotKeys(props: GlobalProps) {
       children={props.children}
     />
   );
-}
+})
 
 // local hotkeys
 function handleEditorKeyDown(e: React.KeyboardEvent, editorState: EditorState) {
@@ -186,7 +186,7 @@ function handleEditorKeyDown(e: React.KeyboardEvent, editorState: EditorState) {
   }
 }
 
-export function EditorHotKeys(props: Props) {
+export const EditorHotKeys = React.memo((props: Props) => {
   const editorState = useContext(EditorContext);
   const onKeyDown = useCallback(
     (e: React.KeyboardEvent) => handleEditorKeyDown(e, editorState),
@@ -200,9 +200,9 @@ export function EditorHotKeys(props: Props) {
       children={props.children}
     />
   );
-}
+})
 
-export function CustomShortcutWrapper(props: { children: React.ReactNode }) {
+export const CustomShortcutWrapper = React.memo((props: { children: React.ReactNode }) => {
   const editorState = useContext(EditorContext);
   const handleCustomShortcut = useCallback(
     (e: KeyboardEvent) => {
@@ -215,4 +215,4 @@ export function CustomShortcutWrapper(props: { children: React.ReactNode }) {
       {props.children}
     </GlobalShortcutsWrapper>
   );
-}
+})
diff --git a/client/packages/lowcoder/src/pages/editor/editorView.tsx b/client/packages/lowcoder/src/pages/editor/editorView.tsx
index fde188950..8be40d20e 100644
--- a/client/packages/lowcoder/src/pages/editor/editorView.tsx
+++ b/client/packages/lowcoder/src/pages/editor/editorView.tsx
@@ -577,4 +577,4 @@ function EditorView(props: EditorViewProps) {
   );
 }
 
-export default EditorView;
+export default React.memo(EditorView);
diff --git a/client/packages/lowcoder/src/pages/editor/right/RightPanel.tsx b/client/packages/lowcoder/src/pages/editor/right/RightPanel.tsx
index 0ad73e171..e89d959e8 100644
--- a/client/packages/lowcoder/src/pages/editor/right/RightPanel.tsx
+++ b/client/packages/lowcoder/src/pages/editor/right/RightPanel.tsx
@@ -9,6 +9,7 @@ import { AttributeIcon } from "lowcoder-design";
 import { InsertIcon } from "lowcoder-design";
 import { trans } from "i18n";
 import { isAggregationApp } from "util/appUtils";
+import React from "react";
 
 type RightPanelProps = {
   onTabChange: (key: string) => void;
@@ -17,7 +18,7 @@ type RightPanelProps = {
   uiComp?: InstanceType<typeof UIComp>;
 };
 
-export default function RightPanel(props: RightPanelProps) {
+function RightPanel(props: RightPanelProps) {
   const { onTabChange, showPropertyPane, uiComp } = props;
   const uiCompType = uiComp && (uiComp.children.compType.getView() as UiLayoutType);
   const aggregationApp = uiCompType && isAggregationApp(uiCompType);
@@ -55,3 +56,5 @@ export default function RightPanel(props: RightPanelProps) {
     </RightPanelWrapper>
   );
 }
+
+export default React.memo(RightPanel);
diff --git a/client/packages/lowcoder/src/pages/tutorials/editorTutorials.tsx b/client/packages/lowcoder/src/pages/tutorials/editorTutorials.tsx
index b1ffe9a72..4e414590e 100644
--- a/client/packages/lowcoder/src/pages/tutorials/editorTutorials.tsx
+++ b/client/packages/lowcoder/src/pages/tutorials/editorTutorials.tsx
@@ -33,6 +33,7 @@ import { i18nObjs } from "../../i18n/index";
 import { DatasourceInfo, HttpConfig } from "api/datasourceApi";
 import { enObj } from "i18n/locales";
 import { QUICK_REST_API_ID } from "constants/datasourceConstants";
+import React from "react";
 
 const tourSteps: Step[] = [
   {
@@ -203,7 +204,7 @@ function addQuery(editorState: EditorState, datasourceInfos: DatasourceInfo[]) {
   editorState.setSelectedBottomRes(queryName, BottomResTypeEnum.Query);
 }
 
-export default function EditorTutorials() {
+function EditorTutorials() {
   const [run, setRun] = useState(false);
   const [stepIndex, setStepIndex] = useState(0);
   const editorState = useContext(EditorContext);
@@ -309,3 +310,5 @@ export default function EditorTutorials() {
     />
   );
 }
+
+export default React.memo(EditorTutorials);

From 5b45716ef97da68cb31835bee75c42009d114276 Mon Sep 17 00:00:00 2001
From: RAHEEL <mraheeliftikhar1994@gmail.com>
Date: Mon, 2 Sep 2024 21:22:02 +0500
Subject: [PATCH 3/5] added memoization

---
 .../comps/containerComp/containerView.tsx     |  30 +-
 .../comps/comps/gridLayoutComp/canvasView.tsx |   9 +-
 .../comps/gridLayoutComp/dragSelector.tsx     |   4 +-
 .../lowcoder/src/comps/comps/rootComp.tsx     |   8 +-
 .../packages/lowcoder/src/layout/gridItem.tsx | 374 ++++++++++++------
 .../lowcoder/src/layout/gridLayout.tsx        |   3 +-
 .../src/pages/editor/appEditorInternal.tsx    |   8 +-
 .../lowcoder/src/pages/editor/editorView.tsx  |   5 +-
 8 files changed, 293 insertions(+), 148 deletions(-)

diff --git a/client/packages/lowcoder/src/comps/comps/containerComp/containerView.tsx b/client/packages/lowcoder/src/comps/comps/containerComp/containerView.tsx
index a1b05a021..c83b94fde 100644
--- a/client/packages/lowcoder/src/comps/comps/containerComp/containerView.tsx
+++ b/client/packages/lowcoder/src/comps/comps/containerComp/containerView.tsx
@@ -24,7 +24,7 @@ import {
   DEFAULT_GRID_COLUMNS,
   DEFAULT_ROW_HEIGHT,
 } from "layout/calculateUtils";
-import _ from "lodash";
+import _, { isEqual } from "lodash";
 import {
   ActionExtraInfo,
   changeChildAction,
@@ -313,7 +313,7 @@ const ItemWrapper = styled.div<{ $disableInteract?: boolean }>`
   pointer-events: ${(props) => (props.$disableInteract ? "none" : "unset")};
 `;
 
-const GridItemWrapper = React.forwardRef(
+const GridItemWrapper = React.memo(React.forwardRef(
   (
     props: React.PropsWithChildren<HTMLAttributes<HTMLDivElement>>,
     ref: React.ForwardedRef<HTMLDivElement>
@@ -326,11 +326,11 @@ const GridItemWrapper = React.forwardRef(
       </ItemWrapper>
     );
   }
-);
+));
 
 type GirdItemViewRecord = Record<string, GridItem>;
 
-export function InnerGrid(props: ViewPropsWithSelect) {
+export const InnerGrid = React.memo((props: ViewPropsWithSelect) => {
   const {
     positionParams,
     rowCount = Infinity,
@@ -385,7 +385,7 @@ export function InnerGrid(props: ViewPropsWithSelect) {
 
   const canAddSelect = useMemo(
     () => _.size(containerSelectNames) === _.size(editorState.selectedCompNames),
-    [containerSelectNames, editorState]
+    [containerSelectNames, editorState.selectedCompNames]
   );
 
   const dispatchPositionParamsTimerRef = useRef(0);
@@ -432,16 +432,21 @@ export function InnerGrid(props: ViewPropsWithSelect) {
       onPositionParamsChange,
       onRowCountChange,
       positionParams,
-      props,
+      props.dispatch,
+      props.containerPadding,
     ]
   );
   const setSelectedNames = useCallback(
     (names: Set<string>) => {
       editorState.setSelectedCompNames(names);
     },
-    [editorState]
+    [editorState.setSelectedCompNames]
   );
-  const { width, ref } = useResizeDetector({ onResize, handleHeight: isRowCountLocked });
+
+  const { width, ref } = useResizeDetector({
+    onResize,
+    handleHeight: isRowCountLocked,
+  });
 
   const itemViewRef = useRef<GirdItemViewRecord>({});
   const itemViews = useMemo(() => {
@@ -464,9 +469,10 @@ export function InnerGrid(props: ViewPropsWithSelect) {
   const clickItem = useCallback(
     (
       e: React.MouseEvent<HTMLDivElement,
-      globalThis.MouseEvent>, name: string
+      globalThis.MouseEvent>,
+      name: string,
     ) => selectItem(e, name, canAddSelect, containerSelectNames, setSelectedNames),
-    [canAddSelect, containerSelectNames, setSelectedNames]
+    [selectItem, canAddSelect, containerSelectNames, setSelectedNames]
   );
 
   useEffect(() => {
@@ -555,7 +561,9 @@ export function InnerGrid(props: ViewPropsWithSelect) {
       {itemViews}
     </ReactGridLayout>
   );
-}
+}, (prevProps, newProps) => {
+  return isEqual(prevProps, newProps);
+});
 
 function selectItem(
   e: MouseEvent<HTMLDivElement>,
diff --git a/client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.tsx b/client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.tsx
index 35f56dca4..cc655730d 100644
--- a/client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.tsx
+++ b/client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.tsx
@@ -1,6 +1,6 @@
 import { EditorContext } from "comps/editorState";
 import { EditorContainer } from "pages/common/styledComponent";
-import { Profiler, useContext, useRef, useState } from "react";
+import React, { Profiler, useContext, useRef, useState } from "react";
 import styled from "styled-components";
 import { profilerCallback } from "util/cacheUtils";
 import {
@@ -20,6 +20,7 @@ import { CanvasContainerID } from "constants/domLocators";
 import { CNRootContainer } from "constants/styleSelectors";
 import { ScrollBar } from "lowcoder-design";
 import { defaultTheme } from "@lowcoder-ee/constants/themeConstants";
+import { isEqual } from "lodash";
 
 // min-height: 100vh;
 
@@ -72,7 +73,7 @@ function getDragSelectedNames(
 
 const EmptySet = new Set<string>();
 
-export function CanvasView(props: ContainerBaseProps) {
+export const CanvasView = React.memo((props: ContainerBaseProps) => {
   const editorState = useContext(EditorContext);
   const [dragSelectedComps, setDragSelectedComp] = useState(EmptySet);
   const scrollContainerRef = useRef(null);
@@ -166,4 +167,6 @@ export function CanvasView(props: ContainerBaseProps) {
       </EditorContainer>
     </CanvasContainer>
   );
-}
+}, (prevProps, newProps) => {
+  return isEqual(prevProps, newProps);
+});
diff --git a/client/packages/lowcoder/src/comps/comps/gridLayoutComp/dragSelector.tsx b/client/packages/lowcoder/src/comps/comps/gridLayoutComp/dragSelector.tsx
index 04aa4cc3b..79e017302 100644
--- a/client/packages/lowcoder/src/comps/comps/gridLayoutComp/dragSelector.tsx
+++ b/client/packages/lowcoder/src/comps/comps/gridLayoutComp/dragSelector.tsx
@@ -38,7 +38,7 @@ const InitialState = {
   startPoint: undefined,
 };
 
-export class DragSelector extends React.Component<SectionProps, SectionState> {
+class DragSelectorComp extends React.Component<SectionProps, SectionState> {
   private readonly selectAreaRef: React.RefObject<HTMLDivElement>;
 
   constructor(props: SectionProps) {
@@ -178,3 +178,5 @@ export class DragSelector extends React.Component<SectionProps, SectionState> {
     };
   }
 }
+
+export const DragSelector = React.memo(DragSelectorComp);
diff --git a/client/packages/lowcoder/src/comps/comps/rootComp.tsx b/client/packages/lowcoder/src/comps/comps/rootComp.tsx
index a3080ebb6..5fede0b07 100644
--- a/client/packages/lowcoder/src/comps/comps/rootComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/rootComp.tsx
@@ -32,6 +32,8 @@ import {
 import RefTreeComp from "./refTreeComp";
 import { ExternalEditorContext } from "util/context/ExternalEditorContext";
 import { useUserViewMode } from "util/hooks";
+import React from "react";
+import { isEqual } from "lodash";
 
 const EditorView = lazy(
   () => import("pages/editor/editorView"),
@@ -55,7 +57,7 @@ const childrenMap = {
   preload: PreloadComp,
 };
 
-function RootView(props: RootViewProps) {
+const RootView = React.memo((props: RootViewProps) => {
   const previewTheme = useContext(ThemeContext);
   const { comp, isModuleRoot, ...divProps } = props;
   const [editorState, setEditorState] = useState<EditorState>();
@@ -143,7 +145,9 @@ function RootView(props: RootViewProps) {
       </PropertySectionContext.Provider>
     </div>
   );
-}
+}, (prevProps, nextProps) => {
+  return isEqual(prevProps, nextProps);
+});
 
 /**
  * Root Comp
diff --git a/client/packages/lowcoder/src/layout/gridItem.tsx b/client/packages/lowcoder/src/layout/gridItem.tsx
index 31893f15b..e64836a0a 100644
--- a/client/packages/lowcoder/src/layout/gridItem.tsx
+++ b/client/packages/lowcoder/src/layout/gridItem.tsx
@@ -1,5 +1,5 @@
 import clsx from "clsx";
-import _ from "lodash";
+import _, { isEqual } from "lodash";
 import { UICompType } from "comps/uiCompRegistry";
 import React, {
   DragEvent,
@@ -7,6 +7,7 @@ import React, {
   SyntheticEvent,
   useCallback,
   useContext,
+  useEffect,
   useMemo,
   useRef,
   useState,
@@ -101,8 +102,30 @@ const ResizableStyled = styled(Resizable)<{ $zIndex: number, isDroppable : boole
 /**
  * An individual item within a ReactGridLayout.
  */
-export function GridItem(props: GridItemProps) {
-  const position = calcGridItemPosition(props, props.x, props.y, props.w, props.h);
+export const GridItem = React.memo((props: GridItemProps) => {
+  const position = useMemo(() =>
+    calcGridItemPosition({
+      margin: props.margin,
+      containerPadding: props.containerPadding,
+      containerWidth: props.containerWidth,
+      cols: props.cols,
+      rowHeight: props.rowHeight,
+      maxRows: props.maxRows,
+    }, props.x, props.y, props.w, props.h),
+    [
+      props.margin,
+      props.containerPadding,
+      props.containerWidth,
+      props.cols,
+      props.rowHeight,
+      props.maxRows,
+      props.x,
+      props.y,
+      props.w,
+      props.h,
+      calcGridItemPosition,
+    ]
+  );
   const [resizing, setResizing] = useState<{ width: number; height: number } | undefined>();
   const [dragging, setDragging] = useState<{ top: number; left: number } | undefined>();
   const elementRef = useRef<HTMLDivElement>(null);
@@ -111,28 +134,152 @@ export function GridItem(props: GridItemProps) {
   // record the real height of the comp content
   const itemHeightRef = useRef<number | undefined>(undefined);
 
-  const onDragStart = (e: DragEvent<HTMLDivElement>) => {
+  const onDragStart = useCallback((e: DragEvent<HTMLDivElement>) => {
     e.stopPropagation();
     const { i } = props as Required<GridItemProps>;
     draggingUtils.clearData();
     draggingUtils.setData("i", i);
     e.dataTransfer.setDragImage(TransparentImg, 0, 0);
     props.onDragStart?.(i, e, elementRef.current as HTMLDivElement);
-  };
+  }, [props.i, props.onDragStart]);
 
-  const onDrag = (e: DragEvent<HTMLDivElement>) => {
+  const onDrag = useCallback((e: DragEvent<HTMLDivElement>) => {
     e.stopPropagation();
     const { i } = props as Required<GridItemProps>;
     props.onDrag?.(i, e, elementRef.current as HTMLDivElement);
-  };
+  }, [props.i, props.onDrag]);
 
-  const onDragEnd = (e: DragEvent<HTMLDivElement>) => {
+  const onDragEnd = useCallback((e: DragEvent<HTMLDivElement>) => {
     const { i } = props as Required<GridItemProps>;
     props.onDragEnd?.(i, e, elementRef.current as HTMLDivElement);
     draggingUtils.clearData();
-  };
+  },[props.i, props.onDragEnd]);
 
-  const mixinDraggable = (child: ReactElement, isDraggable: boolean): ReactElement => {
+  /**
+   * Wrapper around drag events to provide more useful data.
+   * All drag events call the function with the given handler name,
+   * with the signature (index, x, y).
+   *
+   * @param  {String} handlerName Handler name to wrap.
+   * @return {Function}           Handler function.
+   */
+  const onResizeHandler = useCallback((
+    e: SyntheticEvent<Element>,
+    { node, size, handle }: ResizeCallbackData,
+    handlerName: "onResizeStart" | "onResize" | "onResizeStop"
+  ): void => {
+    e.preventDefault();
+    e.stopPropagation();
+    const handler = props[handlerName];
+    if (!handler) return;
+    const oldSize = resizing;
+    let localDragging = dragging;
+    let { cols, maxRows, x, y, w, h, i, maxH, minH, minW, maxW } = props;
+    let [xx, yy] = [x, y];
+
+    const resizeNorth = handle.indexOf("n") >= 0;
+    const resizeWest = handle.indexOf("w") >= 0;
+    if (resizeNorth || resizeWest) {
+      if (handlerName === "onResizeStart") {
+        localDragging = {
+          left: position.left,
+          top: position.top,
+        };
+      } else {
+        if (!localDragging) {
+          throw new Error("onResize called before onResizeStart.");
+        }
+        if (handlerName === "onResize") {
+          let deltaX = 0;
+          let deltaY = 0;
+          if (oldSize) {
+            // Left or top handles need repositioning when dragging. Only bottom right can be left alone
+            const delta = calcResizeXY(
+              handle,
+              size.width - oldSize.width,
+              size.height - oldSize.height
+            );
+            [deltaX, deltaY] = [delta.deltaX, delta.deltaY];
+          }
+          localDragging = getDraggingNewPosition(localDragging, deltaX, deltaY);
+        }
+        const xy = calcXY(props, localDragging.top, localDragging.left, props.w, props.h);
+        [xx, yy] = [xy.x, xy.y];
+      }
+    }
+    setResizing(handlerName === "onResizeStop" ? undefined : size);
+    setDragging(handlerName === "onResizeStop" ? undefined : localDragging);
+
+    // Get new XY
+    let { w: ww, h: hh } = calcWH(props, size.width, size.height);
+    // Min/max capping
+    ww = clamp(ww, minW, maxW);
+    hh = clamp(hh, minH, maxH);
+    let boundW = resizeWest ? x + w : cols - x;
+    let boundH = resizeNorth ? y + h : maxRows - y;
+    ww = clamp(ww, 1, boundW);
+    hh = clamp(hh, 1, boundH);
+    handler(i, ww, hh, {
+      e,
+      node,
+      size,
+      handle,
+      x: xx,
+      y: yy,
+    });
+  }, [
+    resizing,
+    dragging,
+    props.cols,
+    props.maxRows,
+    props.x,
+    props.y,
+    props.w,
+    props.h,
+    props.i,
+    props.maxH,
+    props.minH,
+    props.minW,
+    props.maxW,
+    position.left,
+    position.top,
+    calcResizeXY,
+    getDraggingNewPosition,
+    calcXY,
+    calcWH,
+    setResizing,
+    setDragging,
+    clamp,
+  ]);
+
+   /**
+   * onResizeStop event handler
+   * @param  {Event}  e             event data
+   * @param  {Object} callbackData  an object with node and size information
+   */
+  const onResizeStop = useCallback((e: React.SyntheticEvent, callbackData: ResizeCallbackData) => {
+    onResizeHandler(e, callbackData, "onResizeStop");
+  }, [onResizeHandler]);
+
+  /**
+   * onResizeStart event handler
+   * @param  {Event}  e             event data
+   * @param  {Object} callbackData  an object with node and size information
+   */
+  const onResizeStart = useCallback((e: React.SyntheticEvent, callbackData: ResizeCallbackData) => {
+    onResizeHandler(e, callbackData, "onResizeStart");
+  }, [onResizeHandler]);
+
+  /**
+   * onResize event handler
+   * @param  {Event}  e             event data
+   * @param  {Object} callbackData  an object with node and size information
+   */
+  const onResize = useCallback((e: React.SyntheticEvent, callbackData: ResizeCallbackData) => {
+    onResizeHandler(e, callbackData, "onResize");
+  }, [onResizeHandler]);
+
+  const mixinDraggable = useCallback((child: ReactElement, isDraggable: boolean): ReactElement => {
     const { i } = props as Required<GridItemProps>;
     const testSelectorClass = `lowcoder-${props.compType}`;
     return (
@@ -164,7 +311,15 @@ export function GridItem(props: GridItemProps) {
         </IsDroppable.Provider>
       </div>
     );
-  };
+  }, [
+    props.i,
+    props.name,
+    props.compType,
+    onDragStart,
+    onDragEnd,
+    onDrag,
+    editorState.findUIParentContainer,
+  ]);
 
   /**
    * Mix a Resizable instance into a child.
@@ -172,7 +327,7 @@ export function GridItem(props: GridItemProps) {
    * @param  {Object} position  Position object (pixel values)
    * @return {Element}          Child wrapped in Resizable.
    */
-  const mixinResizable = (
+  const mixinResizable = useCallback((
     child: ReactElement,
     position: Position,
     isResizable: boolean,
@@ -210,110 +365,22 @@ export function GridItem(props: GridItemProps) {
         {child}
       </ResizableStyled>
     );
-  };
-
-  /**
-   * onResizeStop event handler
-   * @param  {Event}  e             event data
-   * @param  {Object} callbackData  an object with node and size information
-   */
-  const onResizeStop = (e: React.SyntheticEvent, callbackData: ResizeCallbackData) => {
-    onResizeHandler(e, callbackData, "onResizeStop");
-  };
-
-  /**
-   * onResizeStart event handler
-   * @param  {Event}  e             event data
-   * @param  {Object} callbackData  an object with node and size information
-   */
-  const onResizeStart = (e: React.SyntheticEvent, callbackData: ResizeCallbackData) => {
-    onResizeHandler(e, callbackData, "onResizeStart");
-  };
-
-  /**
-   * onResize event handler
-   * @param  {Event}  e             event data
-   * @param  {Object} callbackData  an object with node and size information
-   */
-  const onResize = (e: React.SyntheticEvent, callbackData: ResizeCallbackData) => {
-    onResizeHandler(e, callbackData, "onResize");
-  };
-
-  /**
-   * Wrapper around drag events to provide more useful data.
-   * All drag events call the function with the given handler name,
-   * with the signature (index, x, y).
-   *
-   * @param  {String} handlerName Handler name to wrap.
-   * @return {Function}           Handler function.
-   */
-  const onResizeHandler = (
-    e: SyntheticEvent<Element>,
-    { node, size, handle }: ResizeCallbackData,
-    handlerName: "onResizeStart" | "onResize" | "onResizeStop"
-  ): void => {
-    e.preventDefault();
-    e.stopPropagation();
-    const handler = props[handlerName];
-    if (!handler) return;
-    const oldSize = resizing;
-    let localDragging = dragging;
-    let { cols, maxRows, x, y, w, h, i, maxH, minH, minW, maxW } = props;
-    let [xx, yy] = [x, y];
-
-    const resizeNorth = handle.indexOf("n") >= 0;
-    const resizeWest = handle.indexOf("w") >= 0;
-    if (resizeNorth || resizeWest) {
-      if (handlerName === "onResizeStart") {
-        localDragging = {
-          left: position.left,
-          top: position.top,
-        };
-      } else {
-        if (!localDragging) {
-          throw new Error("onResize called before onResizeStart.");
-        }
-        if (handlerName === "onResize") {
-          let deltaX = 0;
-          let deltaY = 0;
-          if (oldSize) {
-            // Left or top handles need repositioning when dragging. Only bottom right can be left alone
-            const delta = calcResizeXY(
-              handle,
-              size.width - oldSize.width,
-              size.height - oldSize.height
-            );
-            [deltaX, deltaY] = [delta.deltaX, delta.deltaY];
-          }
-          localDragging = getDraggingNewPosition(localDragging, deltaX, deltaY);
-        }
-        const xy = calcXY(props, localDragging.top, localDragging.left, props.w, props.h);
-        [xx, yy] = [xy.x, xy.y];
-      }
-    }
-    setResizing(handlerName === "onResizeStop" ? undefined : size);
-    setDragging(handlerName === "onResizeStop" ? undefined : localDragging);
-
-    // Get new XY
-    let { w: ww, h: hh } = calcWH(props, size.width, size.height);
-    // Min/max capping
-    ww = clamp(ww, minW, maxW);
-    hh = clamp(hh, minH, maxH);
-    let boundW = resizeWest ? x + w : cols - x;
-    let boundH = resizeNorth ? y + h : maxRows - y;
-    ww = clamp(ww, 1, boundW);
-    hh = clamp(hh, 1, boundH);
-    handler(i, ww, hh, {
-      e,
-      node,
-      size,
-      handle,
-      x: xx,
-      y: yy,
-    });
-  };
+  }, [
+    props.i,
+    props.cols,
+    props.x,
+    props.minW,
+    props.minH,
+    props.maxW,
+    props.maxH,
+    props.resizeHandles,
+    calcGridItemPosition,
+    onResizeStart,
+    onResizeStop,
+    onResize,
+  ]);
 
-  const adjustWrapperHeight = (width?: number, height?: number, src?: string) => {
+  const adjustWrapperHeight = useCallback((width?: number, height?: number, src?: string) => {
     if (_.isNil(height)) return;
     if (!width) {
       width = position.width;
@@ -327,19 +394,27 @@ export function GridItem(props: GridItemProps) {
     if (props.h !== h) {
       props.onHeightChange?.(props.i, h);
     }
-  };
+  }, [
+    props.i,
+    props.h,
+    props.compType,
+    position.width,
+    props.onHeightChange,
+    getGridItemPadding,
+    calcWH,
+  ]);
 
   /**
    * re-calculate the occupied grid-cells
    * called when item size changes and `autoHeight === true`
    */
-  const onInnerSizeChange = (width?: number, height?: number) => {
+  const onInnerSizeChange = useCallback((width?: number, height?: number) => {
     // log.log("onInnerSizeChange. name: ", props.name, " width: ", width, " height: ", height);
     if (!_.isNil(height)) {
       itemHeightRef.current = height;
     }
     adjustWrapperHeight(width, height);
-  };
+  }, [itemHeightRef, adjustWrapperHeight]);
 
   /**
    * re-calculate the occupied gird-cells.
@@ -347,11 +422,11 @@ export function GridItem(props: GridItemProps) {
    *
    * called when item wrapper's size changes and autoHeight === true
    */
-  const onWrapperSizeChange = () => {
+  const onWrapperSizeChange = useCallback(() => {
     adjustWrapperHeight(undefined, itemHeightRef.current);
-  };
+  }, [itemHeightRef, adjustWrapperHeight]);
 
-  const mixinChildWrapper = (child: React.ReactElement): React.ReactElement => {
+  const mixinChildWrapper = useCallback((child: React.ReactElement): React.ReactElement => {
     const {
       i,
       name,
@@ -398,7 +473,27 @@ export function GridItem(props: GridItemProps) {
         {child}
       </CompSelectionWrapper>
     );
-  };
+  }, [
+    props.i,
+    props.h,
+    props.name,
+    props.autoHeight,
+    props.isSelected,
+    props.hidden,
+    props.selectedSize,
+    props.clickItem,
+    props.placeholder,
+    props.showName.bottom,
+    props.showName.top,
+    props.isSelectable,
+    props.isResizable,
+    props.compType,
+    props.resizeHandles,
+    position.top,
+    position.height,
+    onInnerSizeChange,
+    onWrapperSizeChange,
+  ]);
 
   const calcPosition = useCallback((): Position => {
     let width, height, top, left;
@@ -425,8 +520,10 @@ export function GridItem(props: GridItemProps) {
   }, [dragging, position.height, position.left, position.top, position.width, resizing]);
 
   const { isDraggable, isResizable, layoutHide, children, isSelected, clickItem, zIndex } = props;
-  const pos = calcPosition();
-  const render = () => {
+  
+  const pos = useMemo(calcPosition, [calcPosition]);
+  
+  const render = useMemo(() => {
     let child = React.Children.only(children);
     // Create the child element. We clone the existing element but modify its className and style.
     let newChild: React.ReactElement = React.cloneElement(child, {
@@ -470,12 +567,35 @@ export function GridItem(props: GridItemProps) {
     // Draggable support. This is always on, except for with placeholders.
     newChild = mixinDraggable(newChild, isDraggable);
     return newChild;
-  };
+  }, [
+    pos,
+    children,
+    elementRef,
+    resizing,
+    dragging,
+    isDraggable,
+    layoutHide,
+    zIndex,
+    props.name,
+    props.compType,
+    props.className,
+    props.style,
+    props.static,
+    props.autoHeight,
+    props.hidden,
+    setTransform,
+    mixinChildWrapper,
+    mixinResizable,
+    mixinDraggable,
+  ]);
 
-  const renderResult = useMemo(render, [pos, children, layoutHide, isSelected, clickItem]);
+  // const renderResult = useMemo(render, [pos, children, layoutHide, isSelected, clickItem]);
+  const renderResult = useMemo(() => render, [render]);
 
   return renderResult;
-}
+}, (prevProps, newProps) => {
+  return isEqual(prevProps, newProps);
+})
 
 // GridItem.defaultProps = {
 //   className: "",
diff --git a/client/packages/lowcoder/src/layout/gridLayout.tsx b/client/packages/lowcoder/src/layout/gridLayout.tsx
index 77aaf965b..52f4a3a1b 100644
--- a/client/packages/lowcoder/src/layout/gridLayout.tsx
+++ b/client/packages/lowcoder/src/layout/gridLayout.tsx
@@ -1097,7 +1097,8 @@ const LayoutContainer = styled.div<{
   }`}
 `;
 
-export const ReactGridLayout = GridLayout;
+// export const ReactGridLayout = React.memo(GridLayout);
+export const ReactGridLayout = React.memo(GridLayout);
 
 function moveOrResize(
   e: React.KeyboardEvent,
diff --git a/client/packages/lowcoder/src/pages/editor/appEditorInternal.tsx b/client/packages/lowcoder/src/pages/editor/appEditorInternal.tsx
index 02b822e55..1ece41909 100644
--- a/client/packages/lowcoder/src/pages/editor/appEditorInternal.tsx
+++ b/client/packages/lowcoder/src/pages/editor/appEditorInternal.tsx
@@ -24,6 +24,8 @@ import { useUserViewMode } from "../../util/hooks";
 import { QueryApi } from "api/queryApi";
 import { RootCompInstanceType } from "./useRootCompInstance";
 import { getCurrentUser } from "redux/selectors/usersSelectors";
+import React from "react";
+import { isEqual } from "lodash";
 
 /**
  * FIXME: optimize the logic of saving comps
@@ -77,7 +79,7 @@ interface AppEditorInternalViewProps {
   compInstance: RootCompInstanceType;
 }
 
-export function AppEditorInternalView(props: AppEditorInternalViewProps) {
+export const AppEditorInternalView = React.memo((props: AppEditorInternalViewProps) => {
   const isUserViewMode = useUserViewMode();
   const extraExternalEditorState = useSelector(getExternalEditorState);
   const dispatch = useDispatch();
@@ -125,4 +127,6 @@ export function AppEditorInternalView(props: AppEditorInternalViewProps) {
       </ExternalEditorContext.Provider>
     </ConfigProvider>
   );
-}
+}, (prevProps, nextProps) => {
+  return isEqual(prevProps, nextProps)
+});
diff --git a/client/packages/lowcoder/src/pages/editor/editorView.tsx b/client/packages/lowcoder/src/pages/editor/editorView.tsx
index 8be40d20e..42bdf1e91 100644
--- a/client/packages/lowcoder/src/pages/editor/editorView.tsx
+++ b/client/packages/lowcoder/src/pages/editor/editorView.tsx
@@ -54,6 +54,7 @@ import {
 import { isAggregationApp } from "util/appUtils";
 import EditorSkeletonView from "./editorSkeletonView";
 import { getCommonSettings } from "@lowcoder-ee/redux/selectors/commonSettingSelectors";
+import { isEqual } from "lodash";
 
 const LeftContent = lazy(
   () => import('./LeftContent')
@@ -577,4 +578,6 @@ function EditorView(props: EditorViewProps) {
   );
 }
 
-export default React.memo(EditorView);
+export default React.memo(EditorView, (prevProps, newProps) => {
+  return isEqual(prevProps, newProps);
+});

From 031ac84a246985b7cdcc2d96306be5c7bce2bcad Mon Sep 17 00:00:00 2001
From: RAHEEL <mraheeliftikhar1994@gmail.com>
Date: Mon, 2 Sep 2024 21:44:53 +0500
Subject: [PATCH 4/5] minimize /permission requests

---
 .../PermissionDialog/AppPermissionDialog.tsx  |   4 +-
 .../lowcoder/src/pages/common/header.tsx      | 125 +++++++++---------
 .../src/pages/editor/editorSkeletonView.tsx   |   4 +-
 3 files changed, 70 insertions(+), 63 deletions(-)

diff --git a/client/packages/lowcoder/src/components/PermissionDialog/AppPermissionDialog.tsx b/client/packages/lowcoder/src/components/PermissionDialog/AppPermissionDialog.tsx
index 9c0b490a6..3a22c96a4 100644
--- a/client/packages/lowcoder/src/components/PermissionDialog/AppPermissionDialog.tsx
+++ b/client/packages/lowcoder/src/components/PermissionDialog/AppPermissionDialog.tsx
@@ -31,7 +31,7 @@ import { SHARE_TITLE } from "../../constants/apiConstants";
 import { messageInstance } from "lowcoder-design/src/components/GlobalInstances";
 import { default as Divider } from "antd/es/divider";
 
-export const AppPermissionDialog = (props: {
+export const AppPermissionDialog = React.memo((props: {
   applicationId: string;
   visible: boolean;
   onVisibleChange: (visible: boolean) => void;
@@ -148,7 +148,7 @@ export const AppPermissionDialog = (props: {
       }
     />
   );
-};
+});
 
 const InviteInputBtn = styled.div`
   display: flex;
diff --git a/client/packages/lowcoder/src/pages/common/header.tsx b/client/packages/lowcoder/src/pages/common/header.tsx
index ebb948330..4a4ae436f 100644
--- a/client/packages/lowcoder/src/pages/common/header.tsx
+++ b/client/packages/lowcoder/src/pages/common/header.tsx
@@ -25,7 +25,7 @@ import {
 } from "lowcoder-design";
 import { trans } from "i18n";
 import dayjs from "dayjs";
-import { useContext, useState } from "react";
+import { useContext, useEffect, useMemo, useState } from "react";
 import { useDispatch, useSelector } from "react-redux";
 import {
   publishApplication,
@@ -453,67 +453,74 @@ export default function Header(props: HeaderProps) {
     </>
   );
 
-  const headerEnd = showAppSnapshot ? (
-    <HeaderProfile user={user} />
-  ) : (
-    <>
-      {applicationId && (
-        <AppPermissionDialog
-          applicationId={applicationId}
-          visible={permissionDialogVisible}
-          onVisibleChange={(visible) =>
-            !visible && setPermissionDialogVisible(false)
-          }
-        />
-      )}
-      {canManageApp(user, application) && (
-        <GrayBtn onClick={() => setPermissionDialogVisible(true)}>
-          {SHARE_TITLE}
-        </GrayBtn>
-      )}
-      <PreviewBtn buttonType="primary" onClick={() => preview(applicationId)}>
-        {trans("header.preview")}
-      </PreviewBtn>
-
-      <Dropdown
-        className="cypress-header-dropdown"
-        placement="bottomRight"
-        trigger={["click"]}
-        dropdownRender={() => (
-          <DropdownMenuStyled
-            style={{ minWidth: "110px", borderRadius: "4px" }}
-            onClick={(e) => {
-              if (e.key === "deploy") {
-                dispatch(publishApplication({ applicationId }));
-              } else if (e.key === "snapshot") {
-                dispatch(setShowAppSnapshot(true));
-              }
-            }}
-            items={[
-              {
-                key: "deploy",
-                label: (
-                  <CommonTextLabel>{trans("header.deploy")}</CommonTextLabel>
-                ),
-              },
-              {
-                key: "snapshot",
-                label: (
-                  <CommonTextLabel>{trans("header.snapshot")}</CommonTextLabel>
-                ),
-              },
-            ]}
+  const headerEnd = useMemo(() => {
+    return showAppSnapshot ? (
+      <HeaderProfile user={user} />
+    ) : (
+      <>
+        {applicationId && (
+          <AppPermissionDialog
+            applicationId={applicationId}
+            visible={permissionDialogVisible}
+            onVisibleChange={(visible) =>
+              !visible && setPermissionDialogVisible(false)
+            }
           />
         )}
-      >
-        <PackUpBtn buttonType="primary">
-          <PackUpIcon />
-        </PackUpBtn>
-      </Dropdown>
+        {canManageApp(user, application) && (
+          <GrayBtn onClick={() => setPermissionDialogVisible(true)}>
+            {SHARE_TITLE}
+          </GrayBtn>
+        )}
+        <PreviewBtn buttonType="primary" onClick={() => preview(applicationId)}>
+          {trans("header.preview")}
+        </PreviewBtn>
+
+        <Dropdown
+          className="cypress-header-dropdown"
+          placement="bottomRight"
+          trigger={["click"]}
+          dropdownRender={() => (
+            <DropdownMenuStyled
+              style={{ minWidth: "110px", borderRadius: "4px" }}
+              onClick={(e) => {
+                if (e.key === "deploy") {
+                  dispatch(publishApplication({ applicationId }));
+                } else if (e.key === "snapshot") {
+                  dispatch(setShowAppSnapshot(true));
+                }
+              }}
+              items={[
+                {
+                  key: "deploy",
+                  label: (
+                    <CommonTextLabel>{trans("header.deploy")}</CommonTextLabel>
+                  ),
+                },
+                {
+                  key: "snapshot",
+                  label: (
+                    <CommonTextLabel>{trans("header.snapshot")}</CommonTextLabel>
+                  ),
+                },
+              ]}
+            />
+          )}
+        >
+          <PackUpBtn buttonType="primary">
+            <PackUpIcon />
+          </PackUpBtn>
+        </Dropdown>
 
-      <HeaderProfile user={user} />
-    </>
-  );
+        <HeaderProfile user={user} />
+      </>
+    );
+  }, [
+    user,
+    showAppSnapshot,
+    applicationId,
+    permissionDialogVisible,
+  ]);
 
   return (
     <LayoutHeader
diff --git a/client/packages/lowcoder/src/pages/editor/editorSkeletonView.tsx b/client/packages/lowcoder/src/pages/editor/editorSkeletonView.tsx
index a38afd104..96a3d905f 100644
--- a/client/packages/lowcoder/src/pages/editor/editorSkeletonView.tsx
+++ b/client/packages/lowcoder/src/pages/editor/editorSkeletonView.tsx
@@ -59,12 +59,12 @@ export default function EditorSkeletonView() {
   return (
     <>
       <Height100Div>
-        <Header
+        {/* <Header
           panelStatus={panelStatus}
           togglePanel={_.noop}
           editorModeStatus={editorModeStatus}
           toggleEditorModeStatus={_.noop}
-        />
+        /> */}
         <Body>
           <SiderStyled />
           {panelStatus.left && (

From e9ebbcfcbf7f60a34ea07d5ebe08d4b034804282 Mon Sep 17 00:00:00 2001
From: RAHEEL <mraheeliftikhar1994@gmail.com>
Date: Wed, 4 Sep 2024 22:39:49 +0500
Subject: [PATCH 5/5] small updates

---
 .../src/comps/comps/containerComp/containerView.tsx  |  6 ++++--
 client/packages/lowcoder/src/layout/gridItem.tsx     | 12 +++++++++++-
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/client/packages/lowcoder/src/comps/comps/containerComp/containerView.tsx b/client/packages/lowcoder/src/comps/comps/containerComp/containerView.tsx
index c83b94fde..ce9ddac21 100644
--- a/client/packages/lowcoder/src/comps/comps/containerComp/containerView.tsx
+++ b/client/packages/lowcoder/src/comps/comps/containerComp/containerView.tsx
@@ -348,11 +348,13 @@ export const InnerGrid = React.memo((props: ViewPropsWithSelect) => {
 
   // Falk: TODO: Here we can define the inner grid columns dynamically
   //Added By Aqib Mirza
-  const defaultGrid =
-    horizontalGridCells ||
+  const defaultGrid = useMemo(() => {
+    return horizontalGridCells ||
     currentTheme?.gridColumns ||
     defaultTheme?.gridColumns ||
     "12";
+  }, [horizontalGridCells, currentTheme?.gridColumns, defaultTheme?.gridColumns]);
+
   /////////////////////
   const isDroppable =
     useContext(IsDroppable) && (_.isNil(props.isDroppable) || props.isDroppable) && !readOnly;
diff --git a/client/packages/lowcoder/src/layout/gridItem.tsx b/client/packages/lowcoder/src/layout/gridItem.tsx
index e64836a0a..432c9b453 100644
--- a/client/packages/lowcoder/src/layout/gridItem.tsx
+++ b/client/packages/lowcoder/src/layout/gridItem.tsx
@@ -207,6 +207,7 @@ export const GridItem = React.memo((props: GridItemProps) => {
         [xx, yy] = [xy.x, xy.y];
       }
     }
+
     setResizing(handlerName === "onResizeStop" ? undefined : size);
     setDragging(handlerName === "onResizeStop" ? undefined : localDragging);
 
@@ -517,7 +518,16 @@ export const GridItem = React.memo((props: GridItemProps) => {
       left = position.left;
     }
     return { width, height, top, left };
-  }, [dragging, position.height, position.left, position.top, position.width, resizing]);
+  }, [
+    dragging?.top,
+    dragging?.left,
+    position.height,
+    position.left,
+    position.top,
+    position.width,
+    resizing?.width,
+    resizing?.height,
+  ]);
 
   const { isDraggable, isResizable, layoutHide, children, isSelected, clickItem, zIndex } = props;