PromucFlow_constructor/app/client/src/utils/widgetRenderUtils.tsx
balajisoundar 7ba6e5374b
chore: [chart widget] show configuration errors only in editor (#32024)
## Description
- Updated withWidgetProps to inject errors to widget only in canvas mode
- Deleted some stale code that were using the createCanvasWidget
function
   - getCanvasWidgetDsl
   - getMainContainer

Fixes https://github.com/appsmithorg/appsmith/issues/32026

## Automation

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

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!IMPORTANT]  
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/8419000251>
> Commit: `cfaabbfe72c827bc4ed00e76093d74a0071226db`
> Cypress dashboard url: <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=8419000251&attempt=2"
target="_blank">Click here!</a>
> All cypress tests have passed 🎉🎉🎉

<!-- end of auto-generated comment: Cypress test results  -->















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

## Summary by CodeRabbit

- **Refactor**
- Simplified test setups by removing unnecessary mocks and spies across
various test files.
- Enhanced widget error handling in editor mode for improved stability
and user feedback.
- **Tests**
	- Refactored widget rendering utility tests for better error handling.
- **New Features**
- Widgets in editor mode now display error information, aiding in
quicker debugging and development.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2024-03-26 09:49:58 +05:30

191 lines
5.6 KiB
TypeScript

import type {
CanvasWidgetsReduxState,
FlattenedWidgetProps,
} from "reducers/entityReducers/canvasWidgetsReducer";
import type {
WidgetEntity,
WidgetEntityConfig,
} from "@appsmith/entities/DataTree/types";
import type { ConfigTree, DataTree } from "entities/DataTree/dataTreeTypes";
import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
import { pick } from "lodash";
import {
WIDGET_DSL_STRUCTURE_PROPS,
WIDGET_STATIC_PROPS,
} from "constants/WidgetConstants";
import WidgetFactory from "../WidgetProvider/factory";
import type { WidgetProps } from "widgets/BaseWidget";
import type { LoadingEntitiesState } from "reducers/evaluationReducers/loadingEntitiesReducer";
import type { MetaWidgetsReduxState } from "reducers/entityReducers/metaWidgetsReducer";
import type { WidgetError } from "widgets/BaseWidget";
import { get } from "lodash";
import type { DataTreeError } from "utils/DynamicBindingUtils";
import { EVAL_ERROR_PATH } from "utils/DynamicBindingUtils";
export const createCanvasWidget = (
canvasWidget: FlattenedWidgetProps,
evaluatedWidget: WidgetEntity,
evaluatedWidgetConfig: WidgetEntityConfig,
specificChildProps?: string[],
) => {
/**
* WIDGET_DSL_STRUCTURE_PROPS is required for Building the List widget meta widgets
* requiresFlatWidgetChildren and hasMetaWidgets are the keys required.
*/
const widgetStaticProps = pick(canvasWidget, [
...Object.keys({ ...WIDGET_STATIC_PROPS, ...WIDGET_DSL_STRUCTURE_PROPS }),
...(canvasWidget.additionalStaticProps || []),
]);
//Pick required only contents for specific widgets
const evaluatedStaticProps = specificChildProps
? pick(evaluatedWidget, specificChildProps)
: evaluatedWidget;
const widgetProps = {
...evaluatedStaticProps,
...evaluatedWidgetConfig,
...widgetStaticProps,
} as any;
return widgetProps;
};
export function widgetErrorsFromStaticProps(props: Record<string, unknown>) {
/**
* Evaluation Error Map
* {
widgetPropertyName : DataTreeError[]
}
*/
const evaluationErrorMap = get(props, EVAL_ERROR_PATH, {}) as Record<
string,
DataTreeError[]
>;
const widgetErrors: WidgetError[] = [];
Object.keys(evaluationErrorMap).forEach((propertyPath) => {
const propertyErrors = evaluationErrorMap[propertyPath];
propertyErrors.forEach((evalError) => {
const widgetError: WidgetError = {
name: evalError.errorMessage.name,
message: evalError.errorMessage.message,
stack: evalError.raw,
type: "property",
path: propertyPath,
};
widgetErrors.push(widgetError);
});
});
return widgetErrors;
}
const WidgetTypes = WidgetFactory?.widgetTypes;
export const createLoadingWidget = (
canvasWidget: FlattenedWidgetProps,
): WidgetEntity => {
const widgetStaticProps = pick(
canvasWidget,
Object.keys(WIDGET_STATIC_PROPS),
) as WidgetProps;
return {
...widgetStaticProps,
type:
// We don't need to set skeleton type for modals
// since modals are not displayed when the app is loaded
canvasWidget?.type !== "MODAL_WIDGET"
? WidgetTypes.SKELETON_WIDGET
: canvasWidget?.type,
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
bindingPaths: {},
reactivePaths: {},
triggerPaths: {},
validationPaths: {},
logBlackList: {},
isLoading: true,
propertyOverrideDependency: {},
overridingPropertyPaths: {},
privateWidgets: {},
meta: {},
};
};
/**
* Method to build a child widget tree
* This method is used to build the child widgets array for widgets like Form, or List widget,
* That need to know the state of its child or grandChild to derive properties
* This can be replaced with deived properties of the individual widgets
*
* @param canvasWidgets
* @param evaluatedDataTree
* @param loadingEntities
* @param widgetId
* @param requiredWidgetProps
* @returns
*/
export function buildChildWidgetTree(
canvasWidgets: CanvasWidgetsReduxState,
metaWidgets: MetaWidgetsReduxState,
evaluatedDataTree: DataTree,
loadingEntities: LoadingEntitiesState,
configTree: ConfigTree,
widgetId: string,
requiredWidgetProps?: string[],
) {
const parentWidget = canvasWidgets[widgetId] || metaWidgets[widgetId];
// specificChildProps are the only properties required by the parent to derive it's properties
const specificChildProps =
requiredWidgetProps || getWidgetSpecificChildProps(parentWidget.type);
if (parentWidget.children) {
return parentWidget.children.map((childWidgetId) => {
const childWidget =
canvasWidgets[childWidgetId] || metaWidgets[childWidgetId];
const evaluatedWidget = evaluatedDataTree[
childWidget.widgetName
] as WidgetEntity;
const evaluatedWidgetConfig = configTree[
childWidget.widgetName
] as WidgetEntityConfig;
const widget = evaluatedWidget
? createCanvasWidget(
childWidget,
evaluatedWidget,
evaluatedWidgetConfig,
specificChildProps,
)
: createLoadingWidget(childWidget);
widget.isLoading = loadingEntities.has(childWidget.widgetName);
if (widget?.children?.length > 0) {
widget.children = buildChildWidgetTree(
canvasWidgets,
metaWidgets,
evaluatedDataTree,
loadingEntities,
configTree,
childWidgetId,
specificChildProps,
);
}
return widget;
});
}
return [];
}
function getWidgetSpecificChildProps(type: string) {
if (type === "FORM_WIDGET") {
return ["value", "isDirty", "isValid", "isLoading", "children"];
}
}