PromucFlow_constructor/app/client/src/selectors/widgetSelectors.ts
Pawan Kumar 0cc104ed93
chore: update import of AppState to DefaultReduxState (#40494)
We were using the AppState incorrectly in our selectors. We should use
`DefaultRootState` from react-redux.

/ok-to-test tags="@tag.Sanity"

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Refactor**
- Updated state parameter types in numerous selectors and hooks across
the application from a custom application state type to a standard Redux
root state type, enhancing type consistency and maintainability without
impacting functionality or user experience.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/14771101257>
> Commit: 48aef24d9a54ee63d06943128f7545ba0d461172
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=14771101257&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Sanity`
> Spec:
> <hr>Thu, 01 May 2025 07:16:33 UTC
<!-- end of auto-generated comment: Cypress test results  -->
2025-05-01 15:53:37 +05:30

270 lines
7.9 KiB
TypeScript

import { createSelector } from "reselect";
import type { DefaultRootState } from "react-redux";
import type {
CanvasWidgetsReduxState,
FlattenedWidgetProps,
} from "ee/reducers/entityReducers/canvasWidgetsReducer";
import { getExistingWidgetNames } from "sagas/selectors";
import { getNextEntityName } from "utils/AppsmithUtils";
import WidgetFactory from "WidgetProvider/factory";
import {
getAltBlockWidgetSelection,
getFocusedWidget,
getLastSelectedWidget,
getSelectedWidgets,
} from "./ui";
import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants";
import { get } from "lodash";
import { getAppMode } from "ee/selectors/applicationSelectors";
import { APP_MODE } from "entities/App";
import { getIsTableFilterPaneVisible } from "selectors/tableFilterSelectors";
import { getIsAutoHeightWithLimitsChanging } from "utils/hooks/autoHeightUIHooks";
import { getIsPropertyPaneVisible } from "./propertyPaneSelectors";
import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors";
import { selectCombinedPreviewMode } from "./gitModSelectors";
export const getIsDraggingOrResizing = (state: DefaultRootState) =>
state.ui.widgetDragResize.isResizing || state.ui.widgetDragResize.isDragging;
export const getIsResizing = (state: DefaultRootState) =>
state.ui.widgetDragResize.isResizing;
const getCanvasWidgets = (state: DefaultRootState) =>
state.entities.canvasWidgets;
// A selector that gets the modal widget type based on the feature flag
// This will need to be updated once Anvil and WDS are generally available
export const getModalWidgetType = createSelector(
getIsAnvilLayout,
(isAnvilLayout: boolean) => {
let modalWidgetType = "MODAL_WIDGET";
if (isAnvilLayout) {
modalWidgetType = "WDS_MODAL_WIDGET";
}
return modalWidgetType;
},
);
export const getModalWidgets = createSelector(
getCanvasWidgets,
getModalWidgetType,
(widgets, modalWidgetType) => {
const modalWidgets = Object.values(widgets).filter(
(widget: FlattenedWidgetProps) => widget.type === modalWidgetType,
);
if (modalWidgets.length === 0) return undefined;
return modalWidgets;
},
);
export const getModalDropdownList = createSelector(
getModalWidgets,
(modalWidgets) => {
if (!modalWidgets) return undefined;
return modalWidgets.map((widget: FlattenedWidgetProps) => ({
id: widget.widgetId,
label: widget.widgetName,
value: `${widget.widgetName}.name`,
}));
},
);
export const getNextModalName = createSelector(
getExistingWidgetNames,
getModalWidgetType,
(names, modalWidgetType) => {
const prefix =
WidgetFactory.widgetConfigMap.get(modalWidgetType)?.widgetName || "";
return getNextEntityName(prefix, names);
},
);
/**
* Selector to get the parent widget of a particaular widget with id as a prop
*/
export const getParentWidget = createSelector(
getCanvasWidgets,
(state: DefaultRootState, widgetId: string) => widgetId,
(canvasWidgets, widgetId: string): FlattenedWidgetProps | undefined => {
if (canvasWidgets.hasOwnProperty(widgetId)) {
const widget = canvasWidgets[widgetId];
if (widget.parentId && canvasWidgets.hasOwnProperty(widget.parentId)) {
const parent = canvasWidgets[widget.parentId];
return parent;
}
}
return;
},
);
export const getFocusedParentToOpen = createSelector(
getCanvasWidgets,
(state: DefaultRootState) => state.ui.widgetDragResize.focusedWidget,
(canvasWidgets, focusedWidgetId) => {
return getParentToOpenIfAny(focusedWidgetId, canvasWidgets);
},
);
export const getParentToOpenSelector = (widgetId: string) => {
return createSelector(getCanvasWidgets, (canvasWidgets) => {
return getParentToOpenIfAny(widgetId, canvasWidgets);
});
};
// Check if widget is in the list of selected widgets
export const isWidgetSelected = (widgetId?: string) => {
return createSelector(getSelectedWidgets, (widgets): boolean =>
widgetId ? widgets.includes(widgetId) : false,
);
};
export const isWidgetFocused = (widgetId: string) => {
return createSelector(
getFocusedWidget,
(widget): boolean => widget === widgetId,
);
};
// Check if current widget is the last selected widget
export const isCurrentWidgetLastSelected = (widgetId: string) => {
return createSelector(
getLastSelectedWidget,
(widget): boolean => widget === widgetId,
);
};
// Check if current widget is one of multiple selected widgets
export const isMultiSelectedWidget = (widgetId: string) => {
return createSelector(
getSelectedWidgets,
(widgets): boolean => widgets.length > 1 && widgets.includes(widgetId),
);
};
export function getParentToOpenIfAny(
widgetId: string | undefined,
widgets: CanvasWidgetsReduxState,
) {
if (widgetId) {
let widget = get(widgets, widgetId, undefined);
// While this widget has a openParentPropertyPane equal to true
while (widget?.openParentPropertyPane) {
// Get parent widget props
const parent = get(widgets, `${widget.parentId}`, undefined);
// If parent has openParentPropertyPane = false, return the current parent
if (!parent?.openParentPropertyPane) {
return parent;
}
if (parent?.parentId && parent.parentId !== MAIN_CONTAINER_WIDGET_ID) {
widget = get(widgets, `${widget.parentId}`, undefined);
continue;
}
}
}
return;
}
export const shouldWidgetIgnoreClicksSelector = (widgetId: string) => {
return createSelector(
getFocusedWidget,
getIsTableFilterPaneVisible,
(state: DefaultRootState) => state.ui.widgetDragResize.isResizing,
(state: DefaultRootState) => state.ui.widgetDragResize.isDragging,
(state: DefaultRootState) =>
state.ui.canvasSelection.isDraggingForSelection,
getAppMode,
selectCombinedPreviewMode,
getIsAutoHeightWithLimitsChanging,
getAltBlockWidgetSelection,
(
focusedWidgetId,
isTableFilterPaneVisible,
isResizing,
isDragging,
isDraggingForSelection,
appMode,
isPreviewMode,
isAutoHeightWithLimitsChanging,
isWidgetSelectionBlock,
) => {
const isFocused = focusedWidgetId === widgetId;
return (
isDraggingForSelection ||
isResizing ||
isDragging ||
isPreviewMode ||
appMode !== APP_MODE.EDIT ||
!isFocused ||
isTableFilterPaneVisible ||
isAutoHeightWithLimitsChanging ||
isWidgetSelectionBlock
);
},
);
};
export const getSelectedWidgetAncestry = (state: DefaultRootState) =>
state.ui.widgetDragResize.selectedWidgetAncestry;
export const getEntityExplorerWidgetAncestry = (state: DefaultRootState) =>
state.ui.widgetDragResize.entityExplorerAncestry;
export const getEntityExplorerWidgetsToExpand = createSelector(
getEntityExplorerWidgetAncestry,
(selectedWidgetAncestry: string[]) => {
return selectedWidgetAncestry.slice(1);
},
);
export const showWidgetAsSelected = (widgetId: string) => {
return createSelector(
getLastSelectedWidget,
getSelectedWidgets,
(lastSelectedWidgetId, selectedWidgets) => {
return (
lastSelectedWidgetId === widgetId ||
(selectedWidgets.length > 1 && selectedWidgets.includes(widgetId))
);
},
);
};
export const getFirstSelectedWidgetInList = createSelector(
getSelectedWidgets,
(selectedWidgets) => {
return selectedWidgets?.length ? selectedWidgets[0] : undefined;
},
);
export const isCurrentWidgetActiveInPropertyPane = (widgetId: string) => {
return createSelector(
getIsPropertyPaneVisible,
getFirstSelectedWidgetInList,
(isPaneVisible, firstSelectedWidgetId) => {
return isPaneVisible && firstSelectedWidgetId === widgetId;
},
);
};
export const isResizingOrDragging = createSelector(
(state: DefaultRootState) => state.ui.widgetDragResize.isResizing,
(state: DefaultRootState) => state.ui.widgetDragResize.isDragging,
(isResizing, isDragging) => !!isResizing || !!isDragging,
);