## Description Added ESLint rule to force blank lines between statements. 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 --> > [!CAUTION] > 🔴 🔴 🔴 Some tests have failed. > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/10924926728> > Commit: 34f57714a1575ee04e94e03cbcaf95e57a96c86c > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=10924926728&attempt=1&selectiontype=test&testsstatus=failed&specsstatus=fail" target="_blank">Cypress dashboard</a>. > Tags: @tag.All > Spec: > The following are new failures, please fix them before merging the PR: <ol> > <li>cypress/e2e/Regression/ClientSide/Anvil/AnvilModal_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilButtonWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCheckboxGroupWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilCurrencyInputWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilIconButtonWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInlineButtonWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilInputWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilParagraphWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilPhoneInputWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilStatsWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchGroupWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilSwitchWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilTableWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilToolbarButtonWidgetSnapshot_spec.ts > <li>cypress/e2e/Regression/ClientSide/Anvil/Widgets/AnvilZoneSectionWidgetSnapshot_spec.ts</ol> > <a href="https://internal.appsmith.com/app/cypress-dashboard/identified-flaky-tests-65890b3c81d7400d08fa9ee3?branch=master" target="_blank">List of identified flaky tests</a>. > <hr>Wed, 18 Sep 2024 16:33:36 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No --------- Co-authored-by: Valera Melnikov <valera@appsmith.com>
389 lines
13 KiB
TypeScript
389 lines
13 KiB
TypeScript
import equal from "fast-deep-equal/es6";
|
|
import React from "react";
|
|
|
|
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
|
import type { AppState } from "ee/reducers";
|
|
import { checkContainersForAutoHeightAction } from "actions/autoHeightActions";
|
|
import {
|
|
GridDefaults,
|
|
MAIN_CONTAINER_WIDGET_ID,
|
|
RenderModes,
|
|
WIDGET_PADDING,
|
|
} from "constants/WidgetConstants";
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
import { getWidget } from "sagas/selectors";
|
|
import {
|
|
getIsWidgetLoading,
|
|
getWidgetEvalValues,
|
|
} from "selectors/dataTreeSelectors";
|
|
import {
|
|
computeMainContainerWidget,
|
|
getChildWidgets,
|
|
getMainCanvasProps,
|
|
getRenderMode,
|
|
getMetaWidgetChildrenStructure,
|
|
getMetaWidget,
|
|
getIsAutoLayoutMobileBreakPoint,
|
|
getCanvasWidth,
|
|
combinedPreviewModeSelector,
|
|
} from "selectors/editorSelectors";
|
|
import {
|
|
createCanvasWidget,
|
|
createLoadingWidget,
|
|
widgetErrorsFromStaticProps,
|
|
} from "utils/widgetRenderUtils";
|
|
import type { WidgetProps } from "./BaseWidget";
|
|
import type BaseWidget from "./BaseWidget";
|
|
import type { WidgetEntityConfig } from "ee/entities/DataTree/types";
|
|
import { Positioning } from "layoutSystems/common/utils/constants";
|
|
import { isAutoHeightEnabledForWidget } from "./WidgetUtils";
|
|
import { CANVAS_DEFAULT_MIN_HEIGHT_PX } from "constants/AppConstants";
|
|
import { getGoogleMapsApiKey } from "ee/selectors/tenantSelectors";
|
|
import ConfigTreeActions from "utils/configTree";
|
|
import { getSelectedWidgetAncestry } from "../selectors/widgetSelectors";
|
|
import { getWidgetMinMaxDimensionsInPixel } from "layoutSystems/autolayout/utils/flexWidgetUtils";
|
|
import { defaultAutoLayoutWidgets } from "layoutSystems/autolayout/utils/constants";
|
|
import { getFlattenedChildCanvasWidgets } from "selectors/flattenedChildCanvasSelector";
|
|
import { LayoutSystemTypes } from "layoutSystems/types";
|
|
import { getLayoutSystemType } from "selectors/layoutSystemSelectors";
|
|
import { isWidgetSelectedForPropertyPane } from "selectors/propertyPaneSelectors";
|
|
import WidgetFactory from "WidgetProvider/factory";
|
|
import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors";
|
|
import { WidgetProfiler } from "./BaseWidgetHOC/WidgetProfiler";
|
|
import { getAppsmithConfigs } from "ee/configs";
|
|
import { endSpan, startRootSpan } from "UITelemetry/generateTraces";
|
|
const { newRelic } = getAppsmithConfigs();
|
|
|
|
const WIDGETS_WITH_CHILD_WIDGETS = ["LIST_WIDGET", "FORM_WIDGET"];
|
|
const WIDGETS_REQUIRING_SELECTED_ANCESTRY = ["MODAL_WIDGET", "TABS_WIDGET"];
|
|
|
|
function withWidgetProps(WrappedWidget: typeof BaseWidget) {
|
|
function WrappedPropsComponent(
|
|
props: WidgetProps & { skipWidgetPropsHydration?: boolean },
|
|
) {
|
|
const {
|
|
children,
|
|
hasMetaWidgets,
|
|
referencedWidgetId,
|
|
requiresFlatWidgetChildren,
|
|
skipWidgetPropsHydration,
|
|
type,
|
|
widgetId,
|
|
} = props;
|
|
|
|
const span = startRootSpan("withWidgetProps", { widgetType: type });
|
|
const isPreviewMode = useSelector(combinedPreviewModeSelector);
|
|
|
|
const canvasWidget = useSelector((state: AppState) =>
|
|
getWidget(state, widgetId),
|
|
);
|
|
|
|
const mainCanvasWidth = useSelector(getCanvasWidth);
|
|
const metaWidget = useSelector(getMetaWidget(widgetId));
|
|
|
|
const mainCanvasProps = useSelector((state: AppState) =>
|
|
getMainCanvasProps(state),
|
|
);
|
|
const googleMapsApiKey = useSelector(getGoogleMapsApiKey);
|
|
const renderMode = useSelector(getRenderMode);
|
|
|
|
const widgetName = canvasWidget?.widgetName || metaWidget?.widgetName;
|
|
|
|
const evaluatedWidget = useSelector((state: AppState) =>
|
|
getWidgetEvalValues(state, widgetName),
|
|
);
|
|
|
|
const isLoading = useSelector((state: AppState) =>
|
|
getIsWidgetLoading(state, widgetName),
|
|
);
|
|
|
|
const metaWidgetChildrenStructure = useSelector(
|
|
getMetaWidgetChildrenStructure(widgetId, type, hasMetaWidgets),
|
|
equal,
|
|
);
|
|
|
|
const isWidgetSelected = useSelector((state: AppState) =>
|
|
isWidgetSelectedForPropertyPane(state, widgetId),
|
|
);
|
|
|
|
const isMobile = useSelector(getIsAutoLayoutMobileBreakPoint);
|
|
const layoutSystemType = useSelector(getLayoutSystemType);
|
|
const isAnvilLayout = useSelector(getIsAnvilLayout);
|
|
const isAutoLayout = layoutSystemType === LayoutSystemTypes.AUTO;
|
|
|
|
const configTree = ConfigTreeActions.getConfigTree();
|
|
const evaluatedWidgetConfig = configTree[
|
|
canvasWidget?.widgetName
|
|
] as WidgetEntityConfig;
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
const childWidgets = useSelector((state: AppState) => {
|
|
if (!WIDGETS_WITH_CHILD_WIDGETS.includes(type)) return undefined;
|
|
|
|
return getChildWidgets(state, widgetId);
|
|
}, equal);
|
|
|
|
const flattenedChildCanvasWidgets = useSelector((state: AppState) => {
|
|
if (requiresFlatWidgetChildren) {
|
|
return getFlattenedChildCanvasWidgets(
|
|
state,
|
|
referencedWidgetId || widgetId,
|
|
);
|
|
}
|
|
}, equal);
|
|
|
|
const selectedWidgetAncestry: string[] = useSelector((state: AppState) => {
|
|
if (!WIDGETS_REQUIRING_SELECTED_ANCESTRY.includes(type)) {
|
|
return [];
|
|
}
|
|
|
|
return getSelectedWidgetAncestry(state);
|
|
}, equal);
|
|
|
|
let widgetProps: WidgetProps = {} as WidgetProps;
|
|
|
|
const widget = metaWidget || canvasWidget;
|
|
|
|
if (!skipWidgetPropsHydration) {
|
|
const canvasWidgetProps = (() => {
|
|
if (widgetId === MAIN_CONTAINER_WIDGET_ID) {
|
|
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,
|
|
),
|
|
};
|
|
}
|
|
}
|
|
|
|
return evaluatedWidget
|
|
? createCanvasWidget(widget, evaluatedWidget, evaluatedWidgetConfig)
|
|
: createLoadingWidget(widget);
|
|
})();
|
|
|
|
widgetProps = { ...canvasWidgetProps };
|
|
|
|
widgetProps.isMobile = !!isMobile;
|
|
widgetProps.selectedWidgetAncestry = selectedWidgetAncestry || [];
|
|
widgetProps.isWidgetSelected = isWidgetSelected;
|
|
|
|
/**
|
|
* 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
|
|
) {
|
|
const isListWidgetCanvas =
|
|
props.noPad && props.dropDisabled && props.openParentPropertyPane;
|
|
|
|
widgetProps.rightColumn = props.rightColumn;
|
|
|
|
if (isListWidgetCanvas) {
|
|
widgetProps.bottomRow = props.bottomRow;
|
|
widgetProps.minHeight = props.minHeight;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (defaultAutoLayoutWidgets.includes(props.type)) {
|
|
widgetProps.positioning = isAutoLayout
|
|
? Positioning.Vertical
|
|
: Positioning.Fixed;
|
|
}
|
|
|
|
widgetProps.children = children;
|
|
widgetProps.metaWidgetChildrenStructure = metaWidgetChildrenStructure;
|
|
widgetProps.isLoading = isLoading;
|
|
widgetProps.childWidgets = childWidgets;
|
|
widgetProps.flattenedChildCanvasWidgets = flattenedChildCanvasWidgets;
|
|
|
|
/*
|
|
* In Editor, Widgets can ask for error info to be passed to them
|
|
* so they can show them on the UI
|
|
*/
|
|
const needsErrorInfo =
|
|
!isPreviewMode &&
|
|
renderMode === RenderModes.CANVAS &&
|
|
evaluatedWidget &&
|
|
!!WidgetFactory.getConfig(evaluatedWidget?.type)?.needsErrorInfo;
|
|
|
|
widgetProps.errors = needsErrorInfo
|
|
? widgetErrorsFromStaticProps(evaluatedWidget)
|
|
: [];
|
|
}
|
|
|
|
//merging with original props
|
|
widgetProps = {
|
|
...props,
|
|
...widgetProps,
|
|
layoutSystemType,
|
|
renderMode,
|
|
isPreviewMode,
|
|
};
|
|
|
|
// adding google maps api key to widget props (although meant for map widget only)
|
|
widgetProps.googleMapsApiKey = googleMapsApiKey;
|
|
endSpan(span);
|
|
|
|
// isVisible prop defines whether to render a detached widget
|
|
if (
|
|
widgetProps.detachFromLayout &&
|
|
!widgetProps.isVisible &&
|
|
!selectedWidgetAncestry.includes(widgetProps.widgetId)
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
const shouldCollapseWidgetInViewOrPreviewMode =
|
|
!widgetProps.isVisible &&
|
|
!selectedWidgetAncestry.includes(widgetProps.widgetId) &&
|
|
(renderMode === RenderModes.PAGE || isPreviewMode);
|
|
|
|
const shouldResetCollapsedContainerHeightInViewOrPreviewMode =
|
|
widgetProps.isVisible && widgetProps.topRow === widgetProps.bottomRow;
|
|
|
|
const shouldResetCollapsedContainerHeightInCanvasMode =
|
|
widgetProps.topRow === widgetProps.bottomRow &&
|
|
renderMode === RenderModes.CANVAS &&
|
|
!isPreviewMode;
|
|
|
|
widgetProps.mainCanvasWidth = mainCanvasWidth;
|
|
|
|
if (isAnvilLayout) {
|
|
if (shouldCollapseWidgetInViewOrPreviewMode) {
|
|
return null;
|
|
}
|
|
} else {
|
|
// We don't render invisible widgets in view mode
|
|
if (shouldCollapseWidgetInViewOrPreviewMode) {
|
|
// This flag (isMetaWidget) is used to prevent the Auto height saga from updating
|
|
// the List widget Child Widgets. Auto height is disabled in the List widget and
|
|
// this flag serves as a way to avoid any unintended changes to the child widget's height.
|
|
if (
|
|
widgetProps.bottomRow !== widgetProps.topRow &&
|
|
!widgetProps.isMetaWidget
|
|
) {
|
|
dispatch({
|
|
type: ReduxActionTypes.UPDATE_WIDGET_AUTO_HEIGHT,
|
|
payload: {
|
|
widgetId: props.widgetId,
|
|
height: 0,
|
|
},
|
|
});
|
|
}
|
|
|
|
return null;
|
|
} else if (
|
|
shouldResetCollapsedContainerHeightInViewOrPreviewMode ||
|
|
shouldResetCollapsedContainerHeightInCanvasMode
|
|
) {
|
|
// 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());
|
|
}
|
|
}
|
|
|
|
// Sets the min/max height/width of the widget
|
|
if (isAutoLayout) {
|
|
const minMaxDimensions = getWidgetMinMaxDimensionsInPixel(
|
|
widgetProps,
|
|
mainCanvasWidth,
|
|
);
|
|
|
|
widgetProps = {
|
|
...widgetProps,
|
|
minWidth: minMaxDimensions.minWidth
|
|
? minMaxDimensions.minWidth - 2 * WIDGET_PADDING
|
|
: undefined,
|
|
minHeight: minMaxDimensions.minHeight
|
|
? minMaxDimensions.minHeight - 2 * WIDGET_PADDING
|
|
: undefined,
|
|
maxWidth: minMaxDimensions.maxWidth
|
|
? minMaxDimensions.maxWidth - 2 * WIDGET_PADDING
|
|
: undefined,
|
|
maxHeight: minMaxDimensions.maxHeight
|
|
? minMaxDimensions.maxHeight - 2 * WIDGET_PADDING
|
|
: undefined,
|
|
};
|
|
}
|
|
}
|
|
|
|
if (!newRelic.enableNewRelic) {
|
|
return <WrappedWidget {...widgetProps} />;
|
|
}
|
|
|
|
return (
|
|
<WidgetProfiler type={type} widgetId={widgetId}>
|
|
<WrappedWidget {...widgetProps} />
|
|
</WidgetProfiler>
|
|
);
|
|
}
|
|
|
|
return WrappedPropsComponent;
|
|
}
|
|
|
|
export default withWidgetProps;
|