Skip to content

Commit 340957a

Browse files
authored
feat: made changes to expose the App's height and width as part of the appsmith.ui state object (#41339)
## Description Introducing this property as part of appsmith.ui state object, so that it can be used in cases like passing to a custom widget which can help in determining height of the widget with respective to the App's visible height Example of usage below: https://github.com/user-attachments/assets/b19914f9-2248-453f-bbc8-a903f1034210 Additional Info: Controlling this by a feature flag only at the selector level. Could not do it at the component level as one of the dispatch action occurs from a class based component that does not support hooks like useFeatureFlag > [!TIP] > _Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team)._ > > _Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR._ Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.All" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/19159166010> > Commit: 134a977 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=19159166010&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.All` > Spec: > <hr>Fri, 07 Nov 2025 06:39:25 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added viewport dimension tracking (height & width) across the app. * Window dimensions are available in app state and exposed in the data tree for use in responsive logic and bindings. * Initial dimensions are captured on app load so widgets and pages can react to current viewport size (feature guarded by a rollout flag). <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 2af8e36 commit 340957a

File tree

10 files changed

+74
-2
lines changed

10 files changed

+74
-2
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
2+
3+
export const updateWindowDimensions = (height: number, width: number) => ({
4+
type: ReduxActionTypes.UPDATE_WINDOW_DIMENSIONS,
5+
payload: { height, width },
6+
});

app/client/src/ce/constants/ReduxActionConstants.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,10 @@ const AppThemeActionsTypes = {
12351235
RESET_APP_THEME_SUCCESS: "RESET_APP_THEME_SUCCESS",
12361236
};
12371237

1238+
const WindowActionsTypes = {
1239+
UPDATE_WINDOW_DIMENSIONS: "UPDATE_WINDOW_DIMENSIONS",
1240+
};
1241+
12381242
const AppThemeActionErrorTypes = {
12391243
FETCH_APP_THEMES_ERROR: "FETCH_APP_THEMES_ERROR",
12401244
SET_DEFAULT_SELECTED_THEME_ERROR: "SET_DEFAULT_SELECTED_THEME_ERROR",
@@ -1326,6 +1330,7 @@ export const ReduxActionTypes = {
13261330
...AIActionTypes,
13271331
...ApplicationActionTypes,
13281332
...AppThemeActionsTypes,
1333+
...WindowActionsTypes,
13291334
...AppViewActionTypes,
13301335
...AppSettingsActionTypes,
13311336
...BatchUpdateActionTypes,

app/client/src/ce/entities/FeatureFlag.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export const FEATURE_FLAG = {
6565
configure_block_event_tracking_for_anonymous_users:
6666
"configure_block_event_tracking_for_anonymous_users",
6767
release_static_url_enabled: "release_static_url_enabled",
68+
release_window_dimensions_enabled: "release_window_dimensions_enabled",
6869
} as const;
6970

7071
export type FeatureFlag = keyof typeof FEATURE_FLAG;
@@ -118,6 +119,7 @@ export const DEFAULT_FEATURE_FLAG_VALUE: FeatureFlags = {
118119
release_jsobjects_onpageunloadactions_enabled: false,
119120
configure_block_event_tracking_for_anonymous_users: false,
120121
release_static_url_enabled: false,
122+
release_window_dimensions_enabled: false,
121123
};
122124

123125
export const AB_TESTING_EVENT_KEYS = {

app/client/src/ce/reducers/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import type { CrudInfoModalReduxState } from "reducers/uiReducers/crudInfoModalR
4848
import type { FormEvaluationState } from "reducers/evaluationReducers/formEvaluationReducer";
4949
import type { widgetReflow } from "reducers/uiReducers/reflowReducer";
5050
import type { AppThemingState } from "reducers/uiReducers/appThemingReducer";
51+
import type { WindowDimensionsState } from "reducers/uiReducers/windowReducer";
5152
import type { MainCanvasReduxState } from "ee/reducers/uiReducers/mainCanvasReducer";
5253
import type { SettingsReduxState } from "ee/reducers/settingsReducer";
5354
import SettingsReducer from "ee/reducers/settingsReducer";
@@ -147,6 +148,7 @@ export interface AppState {
147148
activeField: ActiveField;
148149
ide: IDEState;
149150
pluginActionEditor: PluginActionEditorState;
151+
windowDimensions: WindowDimensionsState;
150152
};
151153
entities: {
152154
canvasWidgetsStructure: CanvasWidgetStructure;

app/client/src/ce/reducers/uiReducers/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import crudInfoModalReducer from "reducers/uiReducers/crudInfoModalReducer";
3333
import { widgetReflowReducer } from "reducers/uiReducers/reflowReducer";
3434
import jsObjectNameReducer from "reducers/uiReducers/jsObjectNameReducer";
3535
import appThemingReducer from "reducers/uiReducers/appThemingReducer";
36+
import windowReducer from "reducers/uiReducers/windowReducer";
3637
import mainCanvasReducer from "ee/reducers/uiReducers/mainCanvasReducer";
3738
import focusHistoryReducer from "reducers/uiReducers/focusHistoryReducer";
3839
import { editorContextReducer } from "ee/reducers/uiReducers/editorContextReducer";
@@ -85,6 +86,7 @@ export const uiReducerObject = {
8586
crudInfoModal: crudInfoModalReducer,
8687
widgetReflow: widgetReflowReducer,
8788
appTheming: appThemingReducer,
89+
windowDimensions: windowReducer,
8890
mainCanvas: mainCanvasReducer,
8991
appSettingsPane: appSettingsPaneReducer,
9092
focusHistory: focusHistoryReducer,

app/client/src/pages/AppIDE/AppIDE.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import type { Page } from "entities/Page";
3838
import { IDE_HEADER_HEIGHT } from "@appsmith/ads";
3939
import { GitApplicationContextProvider } from "git-artifact-helpers/application/components";
4040
import { AppIDEModals } from "ee/pages/AppIDE/components/AppIDEModals";
41+
import { updateWindowDimensions } from "actions/windowActions";
4142

4243
interface EditorProps {
4344
currentApplicationId?: string;
@@ -60,6 +61,7 @@ interface EditorProps {
6061
isMultiPane: boolean;
6162
widgetConfigBuildSuccess: () => void;
6263
pages: Page[];
64+
updateWindowDimensions: (height: number, width: number) => void;
6365
}
6466

6567
type Props = EditorProps & RouteComponentProps<BuilderRouteParams>;
@@ -86,6 +88,9 @@ class Editor extends Component<Props> {
8688
editorInitializer().then(() => {
8789
this.props.widgetConfigBuildSuccess();
8890
});
91+
92+
// Set initial window dimensions
93+
this.props.updateWindowDimensions(window.innerHeight, window.innerWidth);
8994
}
9095

9196
shouldComponentUpdate(nextProps: Props) {
@@ -274,6 +279,8 @@ const mapDispatchToProps = (dispatch: any) => {
274279
setupPage: (pageId: string) => dispatch(setupPageAction({ id: pageId })),
275280
updateCurrentPage: (pageId: string) => dispatch(updateCurrentPage(pageId)),
276281
widgetConfigBuildSuccess: () => dispatch(widgetInitialisationSuccess()),
282+
updateWindowDimensions: (height: number, width: number) =>
283+
dispatch(updateWindowDimensions(height, width)),
277284
};
278285
};
279286

app/client/src/pages/AppViewer/AppPage/AppPage.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import React, { useEffect, useMemo, useRef } from "react";
22
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
33
import type { CanvasWidgetStructure } from "WidgetProvider/types";
4-
import { useSelector } from "react-redux";
4+
import { useSelector, useDispatch } from "react-redux";
55
import { getAppMode } from "ee/selectors/applicationSelectors";
66
import { APP_MODE } from "entities/App";
77
import { renderAppsmithCanvas } from "layoutSystems/CanvasFactory";
88
import type { WidgetProps } from "widgets/BaseWidget";
99
import { useAppViewerSidebarProperties } from "utils/hooks/useAppViewerSidebarProperties";
1010
import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors";
11+
import { updateWindowDimensions } from "actions/windowActions";
1112

1213
import { PageView, PageViewWrapper } from "./AppPage.styled";
1314
import { useCanvasWidthAutoResize } from "../../hooks/useCanvasWidthAutoResize";
@@ -24,6 +25,7 @@ export function AppPage(props: AppPageProps) {
2425
const { appName, basePageId, canvasWidth, pageName, widgetsStructure } =
2526
props;
2627

28+
const dispatch = useDispatch();
2729
const appMode = useSelector(getAppMode);
2830
const isPublished = appMode === APP_MODE.PUBLISHED;
2931
const isAnvilLayout = useSelector(getIsAnvilLayout);
@@ -46,6 +48,11 @@ export function AppPage(props: AppPageProps) {
4648
});
4749
}, [appName, basePageId, pageName]);
4850

51+
// Set initial window dimensions
52+
useEffect(() => {
53+
dispatch(updateWindowDimensions(window.innerHeight, window.innerWidth));
54+
}, [dispatch]);
55+
4956
return (
5057
<PageViewWrapper
5158
hasPinnedSidebar={hasSidebarPinned}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { createImmerReducer } from "utils/ReducerUtils";
2+
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
3+
import type { ReduxAction } from "actions/ReduxActionTypes";
4+
5+
export interface WindowDimensionsState {
6+
height: number;
7+
width: number;
8+
}
9+
10+
const initialState: WindowDimensionsState = {
11+
height: typeof window !== "undefined" ? window.innerHeight : 0,
12+
width: typeof window !== "undefined" ? window.innerWidth : 0,
13+
};
14+
15+
const windowReducer = createImmerReducer(initialState, {
16+
[ReduxActionTypes.UPDATE_WINDOW_DIMENSIONS]: (
17+
state: WindowDimensionsState,
18+
action: ReduxAction<{ height: number; width: number }>,
19+
) => {
20+
state.height = action.payload.height;
21+
state.width = action.payload.width;
22+
},
23+
});
24+
25+
export default windowReducer;

app/client/src/selectors/dataTreeSelectors.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
import "url-search-params-polyfill";
2929
import type { DefaultRootState } from "react-redux";
3030
import { getSelectedAppThemeProperties } from "./appThemingSelectors";
31+
import { getWindowDimensions } from "./windowSelectors";
3132
import type { LoadingEntitiesState } from "reducers/evaluationReducers/loadingEntitiesReducer";
3233
import _, { get } from "lodash";
3334
import type { EvaluationError } from "utils/DynamicBindingUtils";
@@ -149,6 +150,7 @@ export const getUnevaluatedDataTree = createSelector(
149150
getMetaWidgetsFromUnevaluatedDataTree,
150151
getAppData,
151152
getSelectedAppThemeProperties,
153+
getWindowDimensions,
152154
getCurrentAppWorkspace,
153155
getCurrentApplication,
154156
getCurrentPageName,
@@ -160,6 +162,7 @@ export const getUnevaluatedDataTree = createSelector(
160162
metaWidgets,
161163
appData,
162164
theme,
165+
windowDimensions,
163166
currentWorkspace,
164167
currentApplication,
165168
getCurrentPageName,
@@ -182,12 +185,13 @@ export const getUnevaluatedDataTree = createSelector(
182185
// taking precedence in case the key is the same
183186
store: appData.store,
184187
theme,
188+
ui: windowDimensions,
185189
currentPageName: getCurrentPageName,
186190
workspaceName: currentWorkspace.name,
187191
appName: currentApplication?.name,
188192
currentEnvironmentName,
193+
ENTITY_TYPE: ENTITY_TYPE.APPSMITH,
189194
} as AppsmithEntity;
190-
(dataTree.appsmith as AppsmithEntity).ENTITY_TYPE = ENTITY_TYPE.APPSMITH;
191195
dataTree = { ...dataTree, ...metaWidgets.dataTree };
192196
configTree = { ...configTree, ...metaWidgets.configTree };
193197

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { DefaultRootState } from "react-redux";
2+
import { selectFeatureFlagCheck } from "ee/selectors/featureFlagsSelectors";
3+
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
4+
5+
export const getWindowDimensions = (state: DefaultRootState) => {
6+
const isWindowDimensionsEnabled = selectFeatureFlagCheck(
7+
state,
8+
FEATURE_FLAG.release_window_dimensions_enabled,
9+
);
10+
11+
return isWindowDimensionsEnabled ? state.ui.windowDimensions : undefined;
12+
};

0 commit comments

Comments
 (0)