chore: Add config to widgets to ask for evaluations error and table widget optimisation (#31956)

## Description
- Add `needsErrorInfo` to widget configuration
- Replace usage of `fast-deep-equal` with referential check for
tableData

## Automation

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

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!IMPORTANT]  
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/8370220547>
> Commit: `ded6b16333e1df5d5d55f22df0559ba378f33d9c`
> Cypress dashboard url: <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=8370220547&attempt=1"
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


- **New Features**
- Introduced a mechanism to display evaluation errors directly on
widgets when necessary.
- **Enhancements**
- Simplified data comparison logic in `TableWidgetV2` to improve
performance.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
balajisoundar 2024-03-21 15:16:00 +05:30 committed by GitHub
parent 0e50c57d6b
commit b498c7e9c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 79 additions and 14 deletions

View File

@ -88,6 +88,9 @@ export interface WidgetBaseConfiguration {
// Flag to tell platform to disaplay this widget when search key
// is not matching any widget.
isSearchWildcard?: boolean;
// Flag to tell withWidgetProps HOC to inject evaluation errors into the widget
needsErrorInfo?: boolean;
}
export type WidgetDefaultProps = Partial<WidgetProps> & WidgetConfigProps;

View File

@ -113,6 +113,7 @@ class WidgetFactory {
isCanvas: config.isCanvas,
needsHeightForContent: config.needsHeightForContent,
isSearchWildcard: config.isSearchWildcard,
needsErrorInfo: !!config.needsErrorInfo,
};
WidgetFactory.widgetConfigMap.set(widget.type, Object.freeze(_config));

View File

@ -8,9 +8,29 @@ import type { MetaWidgetsReduxState } from "reducers/entityReducers/metaWidgetsR
import { buildChildWidgetTree, createCanvasWidget } from "./widgetRenderUtils";
import type { FlattenedWidgetProps } from "WidgetProvider/constants";
jest.mock("../WidgetProvider/factory", () => {
const originalModule = jest.requireActual("react-redux");
return {
...originalModule,
default: {
...originalModule.default,
getConfig: (type: string) => {
return {
needsErrorInfo: type === "CHART_WIDGET",
};
},
widgetTypes: {
SKELETON_WIDGET: "SKELETON_WIDGET",
},
},
};
});
describe("createCanvasWidget functionality", () => {
it("returns an empty errors if no evaluations are present", function () {
const canvasWidget = {} as unknown as FlattenedWidgetProps;
const canvasWidget = {
type: "CHART_WIDGET",
} as unknown as FlattenedWidgetProps;
const dataTree = {} as unknown as WidgetEntity;
const response = createCanvasWidget(
@ -22,7 +42,9 @@ describe("createCanvasWidget functionality", () => {
});
it("returns an empty errors if no evaluation errors are present", () => {
const canvasWidget = {} as unknown as FlattenedWidgetProps;
const canvasWidget = {
type: "CHART_WIDGET",
} as unknown as FlattenedWidgetProps;
const dataTree = {
__evaluation__: {},
} as unknown as WidgetEntity;
@ -35,8 +57,10 @@ describe("createCanvasWidget functionality", () => {
expect(response.errors.length).toEqual(0);
});
it("populates __evaluation__ errors inside widget error property", () => {
const canvasWidget = {} as unknown as FlattenedWidgetProps;
it("populates __evaluation__ errors inside widget error property for widgets that has opt in", () => {
const canvasWidget = {
type: "CHART_WIDGET",
} as unknown as FlattenedWidgetProps;
const dataTree = {
__evaluation__: {
@ -66,6 +90,35 @@ describe("createCanvasWidget functionality", () => {
expect(response.errors[0].type).toStrictEqual("property");
expect(response.errors[0].path).toStrictEqual("propertyPath");
});
it("doesn't populates __evaluation__ errors inside widget error property for widget has not opt in", () => {
const canvasWidget = {
type: "TEXT_WIDGET",
} as unknown as FlattenedWidgetProps;
const dataTree = {
__evaluation__: {
errors: {
propertyPath: [
{
errorMessage: {
name: "Validation Error",
message: "Error Message",
},
raw: "Error Message Stack",
},
],
},
},
} as unknown as WidgetEntity;
const response = createCanvasWidget(
canvasWidget,
dataTree,
{} as WidgetEntityConfig,
);
expect(response.errors.length).toEqual(0);
});
});
describe("test EditorUtils methods", () => {
@ -388,7 +441,7 @@ describe("test EditorUtils methods", () => {
reactivePaths: {},
topRow: 4,
triggerPaths: {},
type: undefined,
type: "SKELETON_WIDGET",
validationPaths: {},
widgetId: "3",
widgetName: "three",
@ -408,7 +461,7 @@ describe("test EditorUtils methods", () => {
reactivePaths: {},
topRow: 6,
triggerPaths: {},
type: undefined,
type: "SKELETON_WIDGET",
validationPaths: {},
widgetId: "4",
widgetName: "four",
@ -427,7 +480,7 @@ describe("test EditorUtils methods", () => {
reactivePaths: {},
topRow: 0,
triggerPaths: {},
type: undefined,
type: "SKELETON_WIDGET",
validationPaths: {},
widgetId: "1_meta",
widgetName: "meta_one",
@ -447,7 +500,7 @@ describe("test EditorUtils methods", () => {
reactivePaths: {},
topRow: 0,
triggerPaths: {},
type: undefined,
type: "SKELETON_WIDGET",
validationPaths: {},
widgetId: "2_meta",
widgetName: "meta_two",
@ -465,7 +518,7 @@ describe("test EditorUtils methods", () => {
reactivePaths: {},
topRow: 0,
triggerPaths: {},
type: undefined,
type: "SKELETON_WIDGET",
validationPaths: {},
widgetId: "2",
widgetName: "two",

View File

@ -48,7 +48,17 @@ export const createCanvasWidget = (
...evaluatedWidgetConfig,
...widgetStaticProps,
} as any;
widgetProps.errors = widgetErrorsFromStaticProps(evaluatedStaticProps);
/*
* Widgets can ask for error info to be passed to them so they can show errors on the UI
*/
const needsErrorInfo = WidgetFactory.getConfig(canvasWidget.type)
?.needsErrorInfo;
widgetProps.errors = needsErrorInfo
? widgetErrorsFromStaticProps(evaluatedStaticProps)
: [];
return widgetProps;
};

View File

@ -68,6 +68,7 @@ class ChartWidget extends BaseWidget<ChartWidgetProps, WidgetState> {
iconSVG: IconSVG,
tags: [WIDGET_TAGS.DISPLAY],
needsMeta: true,
needsErrorInfo: true,
searchTags: ["graph", "visuals", "visualisations"],
};
}

View File

@ -942,10 +942,7 @@ class TableWidgetV2 extends BaseWidget<TableWidgetProps, WidgetState> {
//check if necessary we are batching now updates
// Check if tableData is modifed
const isTableDataModified = !equal(
this.props.tableData,
prevProps.tableData,
);
const isTableDataModified = this.props.tableData !== prevProps.tableData;
const { commitBatchMetaUpdates, pushBatchMetaUpdates } = this.props;
// If the user has changed the tableData OR