PromucFlow_constructor/app/client/src/ce/reducers/entityReducers/canvasWidgetsReducer.ts
Ashit Rath a619db59e6
chore: Move existing middlewares to a middlewares folder and added pass through middleware for packages (#39410)
## Description
Move middlewares to a new folder and added an ee specific middleware
`app/client/src/ee/middlewares/PackageMiddleware.ts`.
This will eventually be added to the store but as of now it is detached
since the functionality is incomplete. It will be extended in EE


PR for https://github.com/appsmithorg/appsmith-ee/pull/6324

## 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/13493097420>
> Commit: a0a94db05767a5f3b8e511e6c72252b1f9f22a17
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=13493097420&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.All`
> Spec:
> <hr>Mon, 24 Feb 2025 08:58:32 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**
- Introduced an enterprise middleware that enhances package-specific
functionality.

- **Refactor**
- Improved internal integration by adjusting module access and
reorganizing route handling.
- Updated import paths and consolidated middleware components to
streamline application structure.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-03-05 20:55:35 +05:30

178 lines
5.2 KiB
TypeScript

import { createImmerReducer } from "utils/ReducerUtils";
import type { ReduxAction } from "actions/ReduxActionTypes";
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
import type { WidgetProps } from "widgets/BaseWidget";
import { uniq, get, set } from "lodash";
import type { Diff } from "deep-diff";
import { diff } from "deep-diff";
import {
getCanvasBottomRow,
getCanvasWidgetHeightsToUpdate,
} from "utils/WidgetSizeUtils";
import { klona } from "klona";
import type { UpdateCanvasPayload } from "actions/pageActions";
import type { SetWidgetDynamicPropertyPayload } from "../../../actions/controlActions";
/* This type is an object whose keys are widgetIds and values are arrays with property paths
and property values
For example:
{ "xyz123": [{ propertyPath: "bottomRow", propertyValue: 20 }] }
*/
export type UpdateWidgetsPayload = Record<
string,
Array<{
propertyPath: string;
propertyValue: unknown;
}>
>;
export const initialState: CanvasWidgetsReduxState = {};
export type FlattenedWidgetProps<orType = never> =
| (WidgetProps & {
children?: string[];
})
| orType;
/**
*
* @param updateLayoutDiff
* @returns list of widgets that were updated
*/
export function getUpdatedWidgetLists(
updateLayoutDiff: Diff<
CanvasWidgetsReduxState,
{
[widgetId: string]: WidgetProps;
}
>[],
) {
return uniq(
updateLayoutDiff
.map((diff: Diff<CanvasWidgetsReduxState>) => diff.path?.[0])
.filter((widgetId) => !!widgetId),
);
}
export const handlers = {
[ReduxActionTypes.INIT_CANVAS_LAYOUT]: (
state: CanvasWidgetsReduxState,
action: ReduxAction<UpdateCanvasPayload>,
) => {
const { widgets } = action.payload;
for (const [widgetId, widgetProps] of Object.entries(widgets)) {
if (widgetProps.type === "CANVAS_WIDGET") {
const bottomRow = getCanvasBottomRow(widgetId, widgets);
widgets[widgetId].bottomRow = bottomRow;
}
}
return widgets;
},
[ReduxActionTypes.UPDATE_LAYOUT]: (
state: CanvasWidgetsReduxState,
action: ReduxAction<UpdateCanvasPayload>,
) => {
let listOfUpdatedWidgets;
// if payload has knowledge of which widgets were changed, use that
if (action.payload.updatedWidgetIds) {
listOfUpdatedWidgets = action.payload.updatedWidgetIds;
} // else diff out the widgets that need to be updated
else {
const updatedLayoutDiffs = diff(state, action.payload.widgets);
if (!updatedLayoutDiffs) return state;
listOfUpdatedWidgets = getUpdatedWidgetLists(updatedLayoutDiffs);
}
//update only the widgets that need to be updated.
for (const widgetId of listOfUpdatedWidgets) {
const updatedWidget = action.payload.widgets[widgetId];
if (updatedWidget) {
state[widgetId] = updatedWidget;
} else {
delete state[widgetId];
}
}
const canvasWidgetHeightsToUpdate: Record<string, number> =
getCanvasWidgetHeightsToUpdate(listOfUpdatedWidgets, state);
for (const widgetId in canvasWidgetHeightsToUpdate) {
state[widgetId] = {
...state[widgetId],
bottomRow: canvasWidgetHeightsToUpdate[widgetId],
};
}
},
[ReduxActionTypes.UPDATE_MULTIPLE_WIDGET_PROPERTIES]: (
state: CanvasWidgetsReduxState,
action: ReduxAction<{
widgetsToUpdate: UpdateWidgetsPayload;
shouldEval: boolean;
}>,
) => {
// For each widget whose properties we would like to update
for (const [widgetId, propertyPathsToUpdate] of Object.entries(
action.payload.widgetsToUpdate,
)) {
// Iterate through each property to update in `widgetId`
propertyPathsToUpdate.forEach(({ propertyPath, propertyValue }) => {
const path = `${widgetId}.${propertyPath}`;
// Get original value in reducer
const originalPropertyValue = get(state, path);
// If the original and new values are different
if (propertyValue !== originalPropertyValue)
// Set the new values
set(state, path, propertyValue);
});
}
const canvasWidgetHeightsToUpdate: Record<string, number> =
getCanvasWidgetHeightsToUpdate(
Object.keys(action.payload.widgetsToUpdate),
state,
);
for (const widgetId in canvasWidgetHeightsToUpdate) {
state[widgetId].bottomRow = canvasWidgetHeightsToUpdate[widgetId];
}
},
[ReduxActionTypes.RESET_EDITOR_REQUEST]: () => {
return klona(initialState);
},
[ReduxActionTypes.SET_WIDGET_DYNAMIC_PROPERTY]: (
state: CanvasWidgetsReduxState,
action: ReduxAction<SetWidgetDynamicPropertyPayload>,
) => {
const { isDynamic, propertyPath, widgetId } = action.payload;
const widget = state[widgetId];
// When options JS mode is disabled, reset the optionLabel and optionValue to standard values
if (
widget.type === "WDS_SELECT_WIDGET" &&
propertyPath === "options" &&
!isDynamic
) {
set(state, `${widgetId}.optionLabel`, "label");
set(state, `${widgetId}.optionValue`, "value");
}
return state;
},
};
export interface CanvasWidgetsReduxState {
[widgetId: string]: FlattenedWidgetProps;
}
const canvasWidgetsReducer = createImmerReducer(initialState, handlers);
export default canvasWidgetsReducer;