2022-08-19 10:10:36 +00:00
|
|
|
import equal from "fast-deep-equal/es6";
|
|
|
|
|
import React from "react";
|
|
|
|
|
|
|
|
|
|
import BaseWidget, { WidgetProps } from "./BaseWidget";
|
|
|
|
|
import {
|
2023-02-03 05:47:40 +00:00
|
|
|
GridDefaults,
|
2022-08-19 10:10:36 +00:00
|
|
|
MAIN_CONTAINER_WIDGET_ID,
|
|
|
|
|
RenderModes,
|
|
|
|
|
} from "constants/WidgetConstants";
|
|
|
|
|
import {
|
|
|
|
|
getWidgetEvalValues,
|
|
|
|
|
getIsWidgetLoading,
|
|
|
|
|
} from "selectors/dataTreeSelectors";
|
|
|
|
|
import {
|
|
|
|
|
getMainCanvasProps,
|
|
|
|
|
computeMainContainerWidget,
|
|
|
|
|
getChildWidgets,
|
|
|
|
|
getRenderMode,
|
2023-02-14 16:07:31 +00:00
|
|
|
getMetaWidgetChildrenStructure,
|
|
|
|
|
getMetaWidget,
|
|
|
|
|
getFlattenedChildCanvasWidgets,
|
2022-11-27 17:12:00 +00:00
|
|
|
previewModeSelector,
|
2022-08-19 10:10:36 +00:00
|
|
|
} from "selectors/editorSelectors";
|
2022-08-24 12:16:32 +00:00
|
|
|
import { AppState } from "@appsmith/reducers";
|
2022-11-23 09:48:23 +00:00
|
|
|
import { useDispatch, useSelector } from "react-redux";
|
2022-08-19 10:10:36 +00:00
|
|
|
import { getWidget } from "sagas/selectors";
|
|
|
|
|
import {
|
|
|
|
|
createCanvasWidget,
|
|
|
|
|
createLoadingWidget,
|
|
|
|
|
} from "utils/widgetRenderUtils";
|
2022-12-14 15:02:13 +00:00
|
|
|
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
2022-11-23 09:48:23 +00:00
|
|
|
import { checkContainersForAutoHeightAction } from "actions/autoHeightActions";
|
feat: Non auto height invisible widgets (#20118)
## Description
This PR adds another feature update we had planned for Auto Height
- [ ] For new applications, in View and Preview mode, any widget which
is invisible will let go of its space and collapse if it's either on the
main Canvas or a container-like widget which has Auto-height enabled.
- [ ] Widgets within a container-like Widget, say Tabs, that doesn't
have Auto-height enabled, will now let go of their space if they're
invisible.
- [ ] The experience in Edit mode has not changed.
TL;DR: In new applications, in the Preview and Published _AKA_ View
modes, if a widget is invisible and within an Auto-height-enabled
container like a Tab, a Modal, a Form, or the main Canvas, it will fully
collapse, allowing widgets below it to move up and take its space. This
changes the behavior today prior to the release of this PR for
Auto-height-enabled widgets.
Fixes #19983
Fixes #18681
2023-02-14 13:36:19 +00:00
|
|
|
import { isAutoHeightEnabledForWidget } from "./WidgetUtils";
|
2023-02-03 05:47:40 +00:00
|
|
|
import { CANVAS_DEFAULT_MIN_HEIGHT_PX } from "constants/AppConstants";
|
2023-02-07 09:23:15 +00:00
|
|
|
import { getGoogleMapsApiKey } from "ce/selectors/tenantSelectors";
|
2022-08-19 10:10:36 +00:00
|
|
|
|
|
|
|
|
const WIDGETS_WITH_CHILD_WIDGETS = ["LIST_WIDGET", "FORM_WIDGET"];
|
|
|
|
|
|
|
|
|
|
function withWidgetProps(WrappedWidget: typeof BaseWidget) {
|
|
|
|
|
function WrappedPropsComponent(
|
|
|
|
|
props: WidgetProps & { skipWidgetPropsHydration?: boolean },
|
|
|
|
|
) {
|
2023-02-14 16:07:31 +00:00
|
|
|
const {
|
|
|
|
|
children,
|
|
|
|
|
hasMetaWidgets,
|
|
|
|
|
referencedWidgetId,
|
|
|
|
|
requiresFlatWidgetChildren,
|
|
|
|
|
skipWidgetPropsHydration,
|
|
|
|
|
type,
|
|
|
|
|
widgetId,
|
|
|
|
|
} = props;
|
2022-11-27 17:12:00 +00:00
|
|
|
const isPreviewMode = useSelector(previewModeSelector);
|
2022-08-19 10:10:36 +00:00
|
|
|
const canvasWidget = useSelector((state: AppState) =>
|
|
|
|
|
getWidget(state, widgetId),
|
|
|
|
|
);
|
2023-02-14 16:07:31 +00:00
|
|
|
const metaWidget = useSelector(getMetaWidget(widgetId));
|
|
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
const mainCanvasProps = useSelector((state: AppState) =>
|
|
|
|
|
getMainCanvasProps(state),
|
|
|
|
|
);
|
2023-02-07 09:23:15 +00:00
|
|
|
const googleMapsApiKey = useSelector(getGoogleMapsApiKey);
|
2022-08-19 10:10:36 +00:00
|
|
|
const renderMode = useSelector(getRenderMode);
|
2023-02-14 16:07:31 +00:00
|
|
|
|
|
|
|
|
const widgetName = canvasWidget?.widgetName || metaWidget?.widgetName;
|
|
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
const evaluatedWidget = useSelector((state: AppState) =>
|
2023-02-14 16:07:31 +00:00
|
|
|
getWidgetEvalValues(state, widgetName),
|
2022-08-19 10:10:36 +00:00
|
|
|
);
|
|
|
|
|
const isLoading = useSelector((state: AppState) =>
|
2023-02-14 16:07:31 +00:00
|
|
|
getIsWidgetLoading(state, widgetName),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const metaWidgetChildrenStructure = useSelector(
|
|
|
|
|
getMetaWidgetChildrenStructure(widgetId, type, hasMetaWidgets),
|
|
|
|
|
equal,
|
2022-08-19 10:10:36 +00:00
|
|
|
);
|
|
|
|
|
|
2022-11-23 09:48:23 +00:00
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
const childWidgets = useSelector((state: AppState) => {
|
|
|
|
|
if (!WIDGETS_WITH_CHILD_WIDGETS.includes(type)) return undefined;
|
|
|
|
|
return getChildWidgets(state, widgetId);
|
|
|
|
|
}, equal);
|
|
|
|
|
|
2023-02-14 16:07:31 +00:00
|
|
|
const flattenedChildCanvasWidgets = useSelector((state: AppState) => {
|
|
|
|
|
if (requiresFlatWidgetChildren) {
|
|
|
|
|
return getFlattenedChildCanvasWidgets(
|
|
|
|
|
state,
|
|
|
|
|
referencedWidgetId || widgetId,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}, equal);
|
|
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
let widgetProps: WidgetProps = {} as WidgetProps;
|
2023-02-14 16:07:31 +00:00
|
|
|
const widget = metaWidget || canvasWidget;
|
2022-08-19 10:10:36 +00:00
|
|
|
|
|
|
|
|
if (!skipWidgetPropsHydration) {
|
|
|
|
|
const canvasWidgetProps = (() => {
|
|
|
|
|
if (widgetId === MAIN_CONTAINER_WIDGET_ID) {
|
2023-02-03 05:47:40 +00:00
|
|
|
const computed = computeMainContainerWidget(
|
|
|
|
|
canvasWidget,
|
|
|
|
|
mainCanvasProps,
|
|
|
|
|
);
|
|
|
|
|
if (renderMode === RenderModes.CANVAS) {
|
|
|
|
|
return {
|
|
|
|
|
...computed,
|
|
|
|
|
bottomRow: Math.max(
|
|
|
|
|
computed.minHeight,
|
|
|
|
|
computed.bottomRow +
|
|
|
|
|
GridDefaults.MAIN_CANVAS_EXTENSION_OFFSET *
|
|
|
|
|
GridDefaults.DEFAULT_GRID_ROW_HEIGHT,
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
return {
|
|
|
|
|
...computed,
|
|
|
|
|
bottomRow: Math.max(
|
|
|
|
|
CANVAS_DEFAULT_MIN_HEIGHT_PX,
|
|
|
|
|
computed.bottomRow +
|
|
|
|
|
GridDefaults.VIEW_MODE_MAIN_CANVAS_EXTENSION_OFFSET *
|
|
|
|
|
GridDefaults.DEFAULT_GRID_ROW_HEIGHT,
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
}
|
2022-08-19 10:10:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return evaluatedWidget
|
2023-02-14 16:07:31 +00:00
|
|
|
? createCanvasWidget(widget, evaluatedWidget)
|
|
|
|
|
: createLoadingWidget(widget);
|
2022-08-19 10:10:36 +00:00
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
widgetProps = { ...canvasWidgetProps };
|
2022-11-23 09:48:23 +00:00
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
/**
|
|
|
|
|
* MODAL_WIDGET by default is to be hidden unless the isVisible property is found.
|
|
|
|
|
* If the isVisible property is undefined and the widget is MODAL_WIDGET then isVisible
|
|
|
|
|
* is set to false
|
|
|
|
|
* If the isVisible property is undefined and the widget is not MODAL_WIDGET then isVisible
|
|
|
|
|
* is set to true
|
|
|
|
|
*/
|
|
|
|
|
widgetProps.isVisible =
|
|
|
|
|
canvasWidgetProps.isVisible ??
|
|
|
|
|
canvasWidgetProps.type !== "MODAL_WIDGET";
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
props.type === "CANVAS_WIDGET" &&
|
|
|
|
|
widgetId !== MAIN_CONTAINER_WIDGET_ID
|
|
|
|
|
) {
|
2022-11-24 18:40:06 +00:00
|
|
|
const isListWidgetCanvas =
|
|
|
|
|
props.noPad && props.dropDisabled && props.openParentPropertyPane;
|
|
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
widgetProps.rightColumn = props.rightColumn;
|
2023-02-03 05:47:40 +00:00
|
|
|
if (isListWidgetCanvas) {
|
2022-11-23 09:48:23 +00:00
|
|
|
widgetProps.bottomRow = props.bottomRow;
|
|
|
|
|
widgetProps.minHeight = props.minHeight;
|
|
|
|
|
}
|
2023-02-03 05:47:40 +00:00
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
widgetProps.shouldScrollContents = props.shouldScrollContents;
|
|
|
|
|
widgetProps.canExtend = props.canExtend;
|
|
|
|
|
widgetProps.parentId = props.parentId;
|
|
|
|
|
} else if (widgetId !== MAIN_CONTAINER_WIDGET_ID) {
|
|
|
|
|
widgetProps.parentColumnSpace = props.parentColumnSpace;
|
|
|
|
|
widgetProps.parentRowSpace = props.parentRowSpace;
|
|
|
|
|
widgetProps.parentId = props.parentId;
|
|
|
|
|
// Form Widget Props
|
|
|
|
|
widgetProps.onReset = props.onReset;
|
|
|
|
|
if ("isFormValid" in props) widgetProps.isFormValid = props.isFormValid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
widgetProps.children = children;
|
2023-02-14 16:07:31 +00:00
|
|
|
widgetProps.metaWidgetChildrenStructure = metaWidgetChildrenStructure;
|
2022-08-19 10:10:36 +00:00
|
|
|
widgetProps.isLoading = isLoading;
|
|
|
|
|
widgetProps.childWidgets = childWidgets;
|
2023-02-14 16:07:31 +00:00
|
|
|
widgetProps.flattenedChildCanvasWidgets = flattenedChildCanvasWidgets;
|
2022-08-19 10:10:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//merging with original props
|
|
|
|
|
widgetProps = { ...props, ...widgetProps, renderMode };
|
|
|
|
|
|
2023-02-07 09:23:15 +00:00
|
|
|
// adding google maps api key to widget props (although meant for map widget only)
|
|
|
|
|
widgetProps.googleMapsApiKey = googleMapsApiKey;
|
|
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
// isVisible prop defines whether to render a detached widget
|
|
|
|
|
if (widgetProps.detachFromLayout && !widgetProps.isVisible) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-23 09:48:23 +00:00
|
|
|
const shouldCollapseWidgetInViewOrPreviewMode =
|
|
|
|
|
!widgetProps.isVisible &&
|
2022-11-27 17:12:00 +00:00
|
|
|
(renderMode === RenderModes.PAGE || isPreviewMode);
|
2022-11-23 09:48:23 +00:00
|
|
|
|
|
|
|
|
const shouldResetCollapsedContainerHeightInViewOrPreviewMode =
|
|
|
|
|
widgetProps.isVisible && widgetProps.topRow === widgetProps.bottomRow;
|
|
|
|
|
|
|
|
|
|
const shouldResetCollapsedContainerHeightInCanvasMode =
|
|
|
|
|
widgetProps.topRow === widgetProps.bottomRow &&
|
2022-11-27 17:12:00 +00:00
|
|
|
renderMode === RenderModes.CANVAS &&
|
|
|
|
|
!isPreviewMode;
|
2022-11-23 09:48:23 +00:00
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
// We don't render invisible widgets in view mode
|
2022-11-23 09:48:23 +00:00
|
|
|
if (shouldCollapseWidgetInViewOrPreviewMode) {
|
2022-11-27 17:12:00 +00:00
|
|
|
if (widgetProps.bottomRow !== widgetProps.topRow) {
|
|
|
|
|
dispatch({
|
|
|
|
|
type: ReduxActionTypes.UPDATE_WIDGET_AUTO_HEIGHT,
|
|
|
|
|
payload: {
|
|
|
|
|
widgetId: props.widgetId,
|
|
|
|
|
height: 0,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-08-19 10:10:36 +00:00
|
|
|
return null;
|
2022-11-23 09:48:23 +00:00
|
|
|
} else if (
|
|
|
|
|
shouldResetCollapsedContainerHeightInViewOrPreviewMode ||
|
|
|
|
|
shouldResetCollapsedContainerHeightInCanvasMode
|
|
|
|
|
) {
|
feat: Non auto height invisible widgets (#20118)
## Description
This PR adds another feature update we had planned for Auto Height
- [ ] For new applications, in View and Preview mode, any widget which
is invisible will let go of its space and collapse if it's either on the
main Canvas or a container-like widget which has Auto-height enabled.
- [ ] Widgets within a container-like Widget, say Tabs, that doesn't
have Auto-height enabled, will now let go of their space if they're
invisible.
- [ ] The experience in Edit mode has not changed.
TL;DR: In new applications, in the Preview and Published _AKA_ View
modes, if a widget is invisible and within an Auto-height-enabled
container like a Tab, a Modal, a Form, or the main Canvas, it will fully
collapse, allowing widgets below it to move up and take its space. This
changes the behavior today prior to the release of this PR for
Auto-height-enabled widgets.
Fixes #19983
Fixes #18681
2023-02-14 13:36:19 +00:00
|
|
|
// We also need to check if a non-auto height widget has collapsed earlier
|
|
|
|
|
// We can figure this out if the widget height is zero and the beforeCollapse
|
|
|
|
|
// topRow and bottomRow are available.
|
|
|
|
|
|
|
|
|
|
// If the above is true, we call an auto height update call
|
|
|
|
|
// so that the widget can be reset correctly.
|
|
|
|
|
if (
|
|
|
|
|
widgetProps.topRow === widgetProps.bottomRow &&
|
|
|
|
|
widgetProps.topRowBeforeCollapse !== undefined &&
|
|
|
|
|
widgetProps.bottomRowBeforeCollapse !== undefined &&
|
|
|
|
|
!isAutoHeightEnabledForWidget(widgetProps)
|
|
|
|
|
) {
|
|
|
|
|
const heightBeforeCollapse =
|
|
|
|
|
(widgetProps.bottomRowBeforeCollapse -
|
|
|
|
|
widgetProps.topRowBeforeCollapse) *
|
|
|
|
|
GridDefaults.DEFAULT_GRID_ROW_HEIGHT;
|
|
|
|
|
dispatch({
|
|
|
|
|
type: ReduxActionTypes.UPDATE_WIDGET_AUTO_HEIGHT,
|
|
|
|
|
payload: {
|
|
|
|
|
widgetId: props.widgetId,
|
|
|
|
|
height: heightBeforeCollapse,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
dispatch(checkContainersForAutoHeightAction());
|
|
|
|
|
}
|
2022-08-19 10:10:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return <WrappedWidget {...widgetProps} />;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return WrappedPropsComponent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default withWidgetProps;
|