2020-03-27 09:02:11 +00:00
|
|
|
import { createSelector } from "reselect";
|
2024-08-06 14:52:22 +00:00
|
|
|
import type { AppState } from "ee/reducers";
|
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
## Description
This PR upgrades Prettier to v2 + enforces TypeScript’s [`import
type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export)
syntax where applicable. It’s submitted as a separate PR so we can merge
it easily.
As a part of this PR, we reformat the codebase heavily:
- add `import type` everywhere where it’s required, and
- re-format the code to account for Prettier 2’s breaking changes:
https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes
This PR is submitted against `release` to make sure all new code by team
members will adhere to new formatting standards, and we’ll have fewer
conflicts when merging `bundle-optimizations` into `release`. (I’ll
merge `release` back into `bundle-optimizations` once this PR is
merged.)
### Why is this needed?
This PR is needed because, for the Lodash optimization from
https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3,
we need to use `import type`. Otherwise, `babel-plugin-lodash` complains
that `LoDashStatic` is not a lodash function.
However, just using `import type` in the current codebase will give you
this:
<img width="962" alt="Screenshot 2023-03-08 at 17 45 59"
src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png">
That’s because Prettier 1 can’t parse `import type` at all. To parse it,
we need to upgrade to Prettier 2.
### Why enforce `import type`?
Apart from just enabling `import type` support, this PR enforces
specifying `import type` everywhere it’s needed. (Developers will get
immediate TypeScript and ESLint errors when they forget to do so.)
I’m doing this because I believe `import type` improves DX and makes
refactorings easier.
Let’s say you had a few imports like below. Can you tell which of these
imports will increase the bundle size? (Tip: it’s not all of them!)
```ts
// app/client/src/workers/Linting/utils.ts
import { Position } from "codemirror";
import { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
It’s pretty hard, right?
What about now?
```ts
// app/client/src/workers/Linting/utils.ts
import type { Position } from "codemirror";
import type { LintError as JSHintError, LintOptions } from "jshint";
import { get, isEmpty, isNumber, keys, last, set } from "lodash";
```
Now, it’s clear that only `lodash` will be bundled.
This helps developers to see which imports are problematic, but it
_also_ helps with refactorings. Now, if you want to see where
`codemirror` is bundled, you can just grep for `import \{.*\} from
"codemirror"` – and you won’t get any type-only imports.
This also helps (some) bundlers. Upon transpiling, TypeScript erases
type-only imports completely. In some environment (not ours), this makes
the bundle smaller, as the bundler doesn’t need to bundle type-only
imports anymore.
## Type of change
- Chore (housekeeping or task changes that don't impact user perception)
## How Has This Been Tested?
This was tested to not break the build.
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: Satish Gandham <hello@satishgandham.com>
Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
|
|
|
import type {
|
2022-09-14 06:55:08 +00:00
|
|
|
CanvasWidgetsReduxState,
|
|
|
|
|
FlattenedWidgetProps,
|
|
|
|
|
} from "reducers/entityReducers/canvasWidgetsReducer";
|
2021-09-09 15:10:22 +00:00
|
|
|
import { getExistingWidgetNames } from "sagas/selectors";
|
2020-04-03 09:32:13 +00:00
|
|
|
import { getNextEntityName } from "utils/AppsmithUtils";
|
2020-03-27 09:02:11 +00:00
|
|
|
|
2023-09-06 12:15:04 +00:00
|
|
|
import WidgetFactory from "WidgetProvider/factory";
|
2022-09-15 05:44:11 +00:00
|
|
|
import {
|
2024-03-13 06:23:49 +00:00
|
|
|
getAltBlockWidgetSelection,
|
2022-09-15 05:44:11 +00:00
|
|
|
getFocusedWidget,
|
|
|
|
|
getLastSelectedWidget,
|
|
|
|
|
getSelectedWidgets,
|
|
|
|
|
} from "./ui";
|
2022-09-14 06:55:08 +00:00
|
|
|
import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants";
|
|
|
|
|
import { get } from "lodash";
|
2024-08-06 14:52:22 +00:00
|
|
|
import { getAppMode } from "ee/selectors/applicationSelectors";
|
2022-09-14 06:55:08 +00:00
|
|
|
import { APP_MODE } from "entities/App";
|
|
|
|
|
import { getIsTableFilterPaneVisible } from "selectors/tableFilterSelectors";
|
2022-11-30 07:32:36 +00:00
|
|
|
import { getIsAutoHeightWithLimitsChanging } from "utils/hooks/autoHeightUIHooks";
|
2023-04-07 13:51:35 +00:00
|
|
|
import { getIsPropertyPaneVisible } from "./propertyPaneSelectors";
|
2024-12-31 12:16:11 +00:00
|
|
|
import { combinedPreviewModeSelector } from "./editorSelectors";
|
2024-04-12 17:24:04 +00:00
|
|
|
import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors";
|
2021-09-09 15:10:22 +00:00
|
|
|
|
2022-05-15 13:12:07 +00:00
|
|
|
export const getIsDraggingOrResizing = (state: AppState) =>
|
|
|
|
|
state.ui.widgetDragResize.isResizing || state.ui.widgetDragResize.isDragging;
|
|
|
|
|
|
2022-08-19 10:10:36 +00:00
|
|
|
export const getIsResizing = (state: AppState) =>
|
|
|
|
|
state.ui.widgetDragResize.isResizing;
|
|
|
|
|
|
2020-03-27 09:02:11 +00:00
|
|
|
const getCanvasWidgets = (state: AppState) => state.entities.canvasWidgets;
|
2024-01-26 04:00:57 +00:00
|
|
|
|
|
|
|
|
// 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(
|
2024-04-12 17:24:04 +00:00
|
|
|
getIsAnvilLayout,
|
|
|
|
|
(isAnvilLayout: boolean) => {
|
2024-01-26 04:00:57 +00:00
|
|
|
let modalWidgetType = "MODAL_WIDGET";
|
2024-09-18 16:35:28 +00:00
|
|
|
|
2024-04-12 17:24:04 +00:00
|
|
|
if (isAnvilLayout) {
|
2024-01-26 04:00:57 +00:00
|
|
|
modalWidgetType = "WDS_MODAL_WIDGET";
|
|
|
|
|
}
|
2024-09-18 16:35:28 +00:00
|
|
|
|
2024-01-26 04:00:57 +00:00
|
|
|
return modalWidgetType;
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
export const getModalWidgets = createSelector(
|
2020-03-27 09:02:11 +00:00
|
|
|
getCanvasWidgets,
|
2024-01-26 04:00:57 +00:00
|
|
|
getModalWidgetType,
|
|
|
|
|
(widgets, modalWidgetType) => {
|
2020-03-27 09:02:11 +00:00
|
|
|
const modalWidgets = Object.values(widgets).filter(
|
2024-01-26 04:00:57 +00:00
|
|
|
(widget: FlattenedWidgetProps) => widget.type === modalWidgetType,
|
2020-03-27 09:02:11 +00:00
|
|
|
);
|
2024-09-18 16:35:28 +00:00
|
|
|
|
2020-03-27 09:02:11 +00:00
|
|
|
if (modalWidgets.length === 0) return undefined;
|
2024-09-18 16:35:28 +00:00
|
|
|
|
2024-01-26 04:00:57 +00:00
|
|
|
return modalWidgets;
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
export const getModalDropdownList = createSelector(
|
|
|
|
|
getModalWidgets,
|
|
|
|
|
(modalWidgets) => {
|
|
|
|
|
if (!modalWidgets) return undefined;
|
2020-03-27 09:02:11 +00:00
|
|
|
|
|
|
|
|
return modalWidgets.map((widget: FlattenedWidgetProps) => ({
|
|
|
|
|
id: widget.widgetId,
|
|
|
|
|
label: widget.widgetName,
|
2024-05-02 12:18:53 +00:00
|
|
|
value: `${widget.widgetName}.name`,
|
2020-03-27 09:02:11 +00:00
|
|
|
}));
|
|
|
|
|
},
|
|
|
|
|
);
|
2020-04-03 09:32:13 +00:00
|
|
|
|
|
|
|
|
export const getNextModalName = createSelector(
|
|
|
|
|
getExistingWidgetNames,
|
2024-01-26 04:00:57 +00:00
|
|
|
getModalWidgetType,
|
|
|
|
|
(names, modalWidgetType) => {
|
2021-09-09 15:10:22 +00:00
|
|
|
const prefix =
|
2024-01-26 04:00:57 +00:00
|
|
|
WidgetFactory.widgetConfigMap.get(modalWidgetType)?.widgetName || "";
|
2024-09-18 16:35:28 +00:00
|
|
|
|
2021-09-09 15:10:22 +00:00
|
|
|
return getNextEntityName(prefix, names);
|
|
|
|
|
},
|
2020-04-03 09:32:13 +00:00
|
|
|
);
|
2022-02-09 11:41:47 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Selector to get the parent widget of a particaular widget with id as a prop
|
|
|
|
|
*/
|
|
|
|
|
export const getParentWidget = createSelector(
|
|
|
|
|
getCanvasWidgets,
|
|
|
|
|
(state: AppState, widgetId: string) => widgetId,
|
|
|
|
|
(canvasWidgets, widgetId: string): FlattenedWidgetProps | undefined => {
|
|
|
|
|
if (canvasWidgets.hasOwnProperty(widgetId)) {
|
|
|
|
|
const widget = canvasWidgets[widgetId];
|
2024-09-18 16:35:28 +00:00
|
|
|
|
2022-02-09 11:41:47 +00:00
|
|
|
if (widget.parentId && canvasWidgets.hasOwnProperty(widget.parentId)) {
|
|
|
|
|
const parent = canvasWidgets[widget.parentId];
|
2024-09-18 16:35:28 +00:00
|
|
|
|
2022-02-09 11:41:47 +00:00
|
|
|
return parent;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-09-18 16:35:28 +00:00
|
|
|
|
2022-02-09 11:41:47 +00:00
|
|
|
return;
|
|
|
|
|
},
|
|
|
|
|
);
|
2022-08-19 10:10:36 +00:00
|
|
|
|
|
|
|
|
export const getFocusedParentToOpen = createSelector(
|
|
|
|
|
getCanvasWidgets,
|
|
|
|
|
(state: AppState) => state.ui.widgetDragResize.focusedWidget,
|
|
|
|
|
(canvasWidgets, focusedWidgetId) => {
|
|
|
|
|
return getParentToOpenIfAny(focusedWidgetId, canvasWidgets);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
export const getParentToOpenSelector = (widgetId: string) => {
|
|
|
|
|
return createSelector(getCanvasWidgets, (canvasWidgets) => {
|
|
|
|
|
return getParentToOpenIfAny(widgetId, canvasWidgets);
|
|
|
|
|
});
|
|
|
|
|
};
|
2022-09-14 06:55:08 +00:00
|
|
|
|
|
|
|
|
// Check if widget is in the list of selected widgets
|
2024-05-23 09:32:34 +00:00
|
|
|
export const isWidgetSelected = (widgetId?: string) => {
|
2022-09-14 06:55:08 +00:00
|
|
|
return createSelector(getSelectedWidgets, (widgets): boolean =>
|
2024-05-23 09:32:34 +00:00
|
|
|
widgetId ? widgets.includes(widgetId) : false,
|
2022-09-14 06:55:08 +00:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2024-05-06 08:29:42 +00:00
|
|
|
export const isWidgetFocused = (widgetId: string) => {
|
2022-09-14 06:55:08 +00:00
|
|
|
return createSelector(
|
|
|
|
|
getFocusedWidget,
|
|
|
|
|
(widget): boolean => widget === widgetId,
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Check if current widget is the last selected widget
|
|
|
|
|
export const isCurrentWidgetLastSelected = (widgetId: string) => {
|
|
|
|
|
return createSelector(
|
2022-09-15 05:44:11 +00:00
|
|
|
getLastSelectedWidget,
|
2022-09-14 06:55:08 +00:00
|
|
|
(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: AppState) => state.ui.widgetDragResize.isResizing,
|
|
|
|
|
(state: AppState) => state.ui.widgetDragResize.isDragging,
|
2023-03-07 10:12:15 +00:00
|
|
|
(state: AppState) => state.ui.canvasSelection.isDraggingForSelection,
|
2022-09-14 06:55:08 +00:00
|
|
|
getAppMode,
|
2024-12-31 12:16:11 +00:00
|
|
|
combinedPreviewModeSelector,
|
2022-11-30 07:32:36 +00:00
|
|
|
getIsAutoHeightWithLimitsChanging,
|
2024-03-13 06:23:49 +00:00
|
|
|
getAltBlockWidgetSelection,
|
2022-09-14 06:55:08 +00:00
|
|
|
(
|
|
|
|
|
focusedWidgetId,
|
|
|
|
|
isTableFilterPaneVisible,
|
|
|
|
|
isResizing,
|
|
|
|
|
isDragging,
|
2023-03-07 10:12:15 +00:00
|
|
|
isDraggingForSelection,
|
2022-09-14 06:55:08 +00:00
|
|
|
appMode,
|
2023-04-07 13:51:35 +00:00
|
|
|
isPreviewMode,
|
2022-11-30 07:32:36 +00:00
|
|
|
isAutoHeightWithLimitsChanging,
|
2024-03-13 06:23:49 +00:00
|
|
|
isWidgetSelectionBlock,
|
2022-09-14 06:55:08 +00:00
|
|
|
) => {
|
|
|
|
|
const isFocused = focusedWidgetId === widgetId;
|
|
|
|
|
|
|
|
|
|
return (
|
2023-03-07 10:12:15 +00:00
|
|
|
isDraggingForSelection ||
|
2022-09-14 06:55:08 +00:00
|
|
|
isResizing ||
|
|
|
|
|
isDragging ||
|
2023-04-07 13:51:35 +00:00
|
|
|
isPreviewMode ||
|
2022-09-14 06:55:08 +00:00
|
|
|
appMode !== APP_MODE.EDIT ||
|
|
|
|
|
!isFocused ||
|
2022-11-30 07:32:36 +00:00
|
|
|
isTableFilterPaneVisible ||
|
2024-03-13 06:23:49 +00:00
|
|
|
isAutoHeightWithLimitsChanging ||
|
|
|
|
|
isWidgetSelectionBlock
|
2022-09-14 06:55:08 +00:00
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
};
|
2023-03-23 05:43:07 +00:00
|
|
|
|
|
|
|
|
export const getSelectedWidgetAncestry = (state: AppState) =>
|
|
|
|
|
state.ui.widgetDragResize.selectedWidgetAncestry;
|
|
|
|
|
|
2023-04-10 07:25:14 +00:00
|
|
|
export const getEntityExplorerWidgetAncestry = (state: AppState) =>
|
|
|
|
|
state.ui.widgetDragResize.entityExplorerAncestry;
|
|
|
|
|
|
2023-03-23 05:43:07 +00:00
|
|
|
export const getEntityExplorerWidgetsToExpand = createSelector(
|
2023-04-10 07:25:14 +00:00
|
|
|
getEntityExplorerWidgetAncestry,
|
2023-03-23 05:43:07 +00:00
|
|
|
(selectedWidgetAncestry: string[]) => {
|
|
|
|
|
return selectedWidgetAncestry.slice(1);
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-04-07 13:51:35 +00:00
|
|
|
|
|
|
|
|
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: AppState) => state.ui.widgetDragResize.isResizing,
|
|
|
|
|
(state: AppState) => state.ui.widgetDragResize.isDragging,
|
|
|
|
|
(isResizing, isDragging) => !!isResizing || !!isDragging,
|
|
|
|
|
);
|