fix: Correct x and y values returned for Sankey (custom fusion chart) when onDataPointClick is triggered (#26267)

## Description
We are adding `rawEventData` property to `onDataPointClick` for the
chart widget. Also, when `x` and `y` are not available, we make them
`-1`.

#### PR fixes following issue(s)
Fixes #26026

#### Type of change
- Bug fix (non-breaking change which fixes an issue)

## Testing
>
#### How Has This Been Tested?
- [x] Jest

#### 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
- [x] I have performed a self-review of my own code
- [x] 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
- [x] 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:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
This commit is contained in:
Dhruvik Neharia 2023-08-21 15:00:04 +05:30 committed by GitHub
parent be4a43408c
commit b53bc72f92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 186 additions and 40 deletions

View File

@ -23,6 +23,11 @@ describe("Input widget test with default value from chart datapoint", () => {
});
});
afterEach(() => {
//this is to enable re-attempt passing!
deployMode.NavigateBacktoEditor();
});
it("1. Chart widget - Input widget test with default value from another Input widget", () => {
entityExplorer.SelectEntityByName("Input1", "Widgets");
propPane.UpdatePropertyFieldValue(
@ -55,8 +60,46 @@ describe("Input widget test with default value from chart datapoint", () => {
.should("have.value", dsl.dsl.children[0].chartData[0].seriesName);
});
afterEach(() => {
//this is to enable re-attempt passing!
it("2. onDataPointClick should work and respond with x, y, seriesTitle, and rawEventData (in case of custom fusion chart).", () => {
assertHelper.AssertNetworkStatus("@updateLayout");
entityExplorer.SelectEntityByName("Chart1");
propPane.TogglePropertyState("Show Labels", "On");
propPane.SelectPlatformFunction("onDataPointClick", "Show alert");
agHelper.EnterActionValue("Message", dataSet.bindingDataPoint);
deployMode.DeployApp();
agHelper.Sleep(1500); //waiting for chart to load!
agHelper.GetNClickByContains(widgetLocators.chartDataPoint, "36000");
cy.get(locators._toastMsg).should(
"have.text",
`{"x":"Sun","y":36000,"seriesTitle":"Sales"}`,
);
deployMode.NavigateBacktoEditor();
agHelper.AddDsl("chartCustomSankeyDataDsl");
cy.fixture("chartCustomSankeyDataDsl").then((val: any) => {
dsl = val;
});
cy.fixture("testdata").then(function (data: any) {
dataSet = data;
});
assertHelper.AssertNetworkStatus("@updateLayout");
entityExplorer.SelectEntityByName("Chart1");
propPane.SelectPlatformFunction("onDataPointClick", "Show alert");
agHelper.EnterActionValue("Message", dataSet.bindingDataPoint);
deployMode.DeployApp();
agHelper.Sleep(1500); //waiting for chart to load!
agHelper.GetNClickByContains(
widgetLocators.chartDataPoint,
"European Union",
);
cy.get(locators._toastMsg).should(
"have.text",
`{"x":-1,"y":-1,"seriesTitle":"","rawEventData":{"color":"#FFC533","alpha":100,"labelFill":"#666","labelAlpha":100,"value":4747591,"label":"European Union","sourceLinks":["France","United States","United Kingdom","Switzerland","Austria","Sweden"],"targetLinks":["Netherlands","Germany","Belgium","China","Italy","Russia","Spain"]}}`,
);
});
});

View File

@ -0,0 +1,84 @@
{
"dsl": {
"widgetName": "MainContainer",
"backgroundColor": "none",
"rightColumn": 4896.0,
"snapColumns": 64.0,
"detachFromLayout": true,
"widgetId": "0",
"topRow": 0.0,
"bottomRow": 790.0,
"containerStyle": "none",
"snapRows": 124.0,
"parentRowSpace": 1.0,
"type": "CANVAS_WIDGET",
"canExtend": true,
"version": 85.0,
"minHeight": 1292.0,
"dynamicTriggerPathList": [],
"parentColumnSpace": 1.0,
"dynamicBindingPathList": [],
"leftColumn": 0.0,
"children": [
{
"boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}",
"mobileBottomRow": 43.0,
"widgetName": "Chart1",
"allowScroll": false,
"dynamicPropertyPathList": [],
"displayName": "Chart",
"iconSVG": "/static/media/icon.8eea39845729f7f4bfadeecd3810a09d.svg",
"searchTags": ["graph", "visuals", "visualisations"],
"topRow": 4.0,
"bottomRow": 79.0,
"parentRowSpace": 10.0,
"type": "CHART_WIDGET",
"hideCard": false,
"mobileRightColumn": 29.0,
"chartData": {
"xne7s065jy": {
"seriesName": "2023",
"data": "[\n {\n \"x\": \"Product1\",\n \"y\": 20000\n },\n {\n \"x\": \"Product2\",\n \"y\": 22000\n },\n {\n \"x\": \"Product3\",\n \"y\": 32000\n }\n]"
}
},
"animateLoading": true,
"fontFamily": "{{appsmith.theme.fontFamily.appFont}}",
"parentColumnSpace": 20.078125,
"dynamicTriggerPathList": [{ "key": "onDataPointClick" }],
"leftColumn": 0.0,
"dynamicBindingPathList": [
{ "key": "borderRadius" },
{ "key": "boxShadow" },
{ "key": "accentColor" },
{ "key": "fontFamily" }
],
"customFusionChartConfig": "{\n \"type\": \"sankey\",\n \"dataSource\": {\n \"nodes\": [\n {\n \"label\": \"Netherlands\"\n },\n {\n \"label\": \"Canada\"\n },\n {\n \"label\": \"Belgium\"\n },\n {\n \"label\": \"Italy\"\n },\n {\n \"label\": \"Mexico\"\n },\n {\n \"label\": \"Russia\"\n },\n {\n \"label\": \"Spain\"\n },\n {\n \"label\": \"South Korea\"\n },\n {\n \"label\": \"Germany\"\n },\n {\n \"label\": \"China\"\n },\n {\n \"label\": \"European Union\"\n },\n {\n \"label\": \"Japan\"\n },\n {\n \"label\": \"United Kingdom\"\n },\n {\n \"label\": \"United States\"\n },\n {\n \"label\": \"France\"\n },\n {\n \"label\": \"Hong Kong\"\n },\n {\n \"label\": \"Switzerland\"\n },\n {\n \"label\": \"Austria\"\n },\n {\n \"label\": \"Sweden\"\n }\n ],\n \"links\": [\n {\n \"from\": \"Netherlands\",\n \"to\": \"European Union\",\n \"value\": 798744\n },\n {\n \"from\": \"Germany\",\n \"to\": \"European Union\",\n \"value\": 1468990\n },\n {\n \"from\": \"European Union\",\n \"to\": \"France\",\n \"value\": 745931\n },\n {\n \"from\": \"European Union\",\n \"to\": \"United States\",\n \"value\": 660541\n },\n {\n \"from\": \"Canada\",\n \"to\": \"United States\",\n \"value\": 594546\n },\n {\n \"from\": \"Belgium\",\n \"to\": \"European Union\",\n \"value\": 628796\n },\n {\n \"from\": \"China\",\n \"to\": \"Hong Kong\",\n \"value\": 400571\n },\n {\n \"from\": \"China\",\n \"to\": \"United States\",\n \"value\": 526454\n },\n {\n \"from\": \"European Union\",\n \"to\": \"United Kingdom\",\n \"value\": 520318\n },\n {\n \"from\": \"China\",\n \"to\": \"European Union\",\n \"value\": 560536\n },\n {\n \"from\": \"Italy\",\n \"to\": \"European Union\",\n \"value\": 539556\n },\n {\n \"from\": \"Mexico\",\n \"to\": \"United States\",\n \"value\": 492715\n },\n {\n \"from\": \"Russia\",\n \"to\": \"European Union\",\n \"value\": 385778\n },\n {\n \"from\": \"Spain\",\n \"to\": \"European Union\",\n \"value\": 365191\n },\n {\n \"from\": \"China\",\n \"to\": \"Japan\",\n \"value\": 312062\n },\n {\n \"from\": \"European Union\",\n \"to\": \"Switzerland\",\n \"value\": 328609\n },\n {\n \"from\": \"South Korea\",\n \"to\": \"China\",\n \"value\": 229073\n },\n {\n \"from\": \"European Union\",\n \"to\": \"Austria\",\n \"value\": 244913\n },\n {\n \"from\": \"Japan\",\n \"to\": \"United States\",\n \"value\": 206091\n },\n {\n \"from\": \"European Union\",\n \"to\": \"Sweden\",\n \"value\": 204849\n },\n {\n \"from\": \"Germany\",\n \"to\": \"United States\",\n \"value\": 184287\n }\n ],\n \"chart\": {\n \"caption\": \"Immigrant Flow for Last Month (In Millions)\",\n \"legendPosition\": \"bottom\",\n \"linkcolor\": \"blend\",\n \"theme\": \"fusion\"\n }\n }\n}",
"onDataPointClick": "",
"showDataPointLabel": false,
"key": "8qdt18v5ny",
"isDeprecated": false,
"rightColumn": 64.0,
"widgetId": "1jj1ihohlk",
"accentColor": "{{appsmith.theme.colors.primaryColor}}",
"minWidth": 450.0,
"isVisible": true,
"version": 1.0,
"parentId": "0",
"labelOrientation": "auto",
"tags": ["Display"],
"renderMode": "CANVAS",
"isLoading": false,
"mobileTopRow": 11.0,
"responsiveBehavior": "fill",
"yAxisName": "Revenue($)",
"originalTopRow": 68.0,
"chartName": "Sales Report",
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"mobileLeftColumn": 5.0,
"xAxisName": "Product Line",
"originalBottomRow": 100.0,
"chartType": "CUSTOM_FUSION_CHART"
}
]
}
}

View File

@ -79,7 +79,7 @@
"tableOnRowSelect": ".t--property-control-onrowselected .t--open-dropdown-Select-Action",
"switchInput": ".t--draggable-switchwidget span.t--widget-name",
"switchLabel": ".t--draggable-switchwidget label",
"switch":".bp3-switch",
"switch": ".bp3-switch",
"multiSelectInput": ".t--draggable-multiselectwidget span.t--widget-name",
"multiSelectLabel": ".t--draggable-multiselectwidget label",
"addColumn": ".t--add-column-btn",
@ -202,30 +202,30 @@
"codescannerwidget": ".t--widget-codescannerwidget",
"widgetNameSpan": ".t--widget-propertypane-toggle > .t--widget-name",
"listWidgetv2": ".t--widget-listwidgetv2",
"progressWidget":".t--widget-progresswidget",
"circularProgressWidget":"[data-value='circular']",
"progressWidget": ".t--widget-progresswidget",
"circularProgressWidget": "[data-value='circular']",
"linearProgressWidget": "[data-value='linear']",
"cameraErrorText" : ".error-text:contains('Permission denied')",
"cameraErrorText": ".error-text:contains('Permission denied')",
"cameraVideo": "video",
"cameraWidgetScreen" : "div.fullscreen > div",
"cameraWidgetScreen": "div.fullscreen > div",
"cameraFullscreenBtn": "//div[@class='fullscreen']/div[2]/div/div[3]/button",
"cameraCaptureBtn": "//div[@class='fullscreen']/div[2]/div/div[2]/button",
"cameraStopRecordingBtn": "//div[@class='fullscreen']/div[2]/div/div[2]/button",
"cameraSaveBtn": "//div[@class='fullscreen']/div[2]/div/div[2]/button",
"cameraRefreshBtn": "//div[@class='fullscreen']/div[2]/div/div[2]/button",
"cameraImageVideoOnOffBtn":"//div[@class='fullscreen']/div[2]/div/div[1]/button",
"cameraImageVideoDropdown":"//div[@class='fullscreen']/div[2]/div/div[1]/span/button",
"cameraImageDiscardBtn":"//div[@class='fullscreen']/div[2]/div/div[2]/button[2]",
"cameraImageVideoOnOffBtn": "//div[@class='fullscreen']/div[2]/div/div[1]/button",
"cameraImageVideoDropdown": "//div[@class='fullscreen']/div[2]/div/div[1]/span/button",
"cameraImageDiscardBtn": "//div[@class='fullscreen']/div[2]/div/div[2]/button[2]",
"cameraMicrophoneBtn": "//div[@class='fullscreen']/div[2]/div/div[1]/button[1]",
"cameraMicrophoneDropdown": "//div[@class='fullscreen']/div[2]/div/div[1]/span[1]/button",
"cameraVideoOnOffBtn": "//div[@class='fullscreen']/div[2]/div/div[1]/button[2]",
"cameraVideoDropdown": "//div[@class='fullscreen']/div[2]/div/div[1]/span[2]/button",
"cameraVideoPlayBtn":"//div[@class='fullscreen']/div[2]/div/div[2]/button[2]",
"cameraVideodiscardBtn":"//div[@class='fullscreen']/div[2]/div/div[2]/button[3]",
"codeScannerScreen" : "div.code-scanner-camera-container > div",
"cameraVideoPlayBtn": "//div[@class='fullscreen']/div[2]/div/div[2]/button[2]",
"cameraVideodiscardBtn": "//div[@class='fullscreen']/div[2]/div/div[2]/button[3]",
"codeScannerScreen": "div.code-scanner-camera-container > div",
"codeScannerVideo": "video",
"codeScannerScanButton":"//*[text()='Scan a QR/Barcode']/parent::button",
"codeScannerNewScanButton":"//*[text()='Scan Code']/parent::button",
"codeScannerClose":".code-scanner-close",
"codeScannerScanButton": "//*[text()='Scan a QR/Barcode']/parent::button",
"codeScannerNewScanButton": "//*[text()='Scan Code']/parent::button",
"codeScannerClose": ".code-scanner-close",
"codeScannerModal": ".code-scanner-content"
}

View File

@ -145,11 +145,11 @@ describe("Chart Widget", () => {
});
it("3. adds a click event when user adds a click callback", async () => {
const mockCallback = jest.fn();
const mockCallback = jest.fn((params) => params);
const props = { ...defaultProps };
props.onDataPointClick = (point) => {
point;
mockCallback();
mockCallback(point);
};
render(<ChartComponent {...props} />);

View File

@ -128,6 +128,35 @@ class ChartComponent extends React.Component<
};
}
parseOnDataPointClickParams = (evt: any, chartType: ChartType) => {
if (chartType === "CUSTOM_FUSION_CHART") {
const data = evt.data;
const seriesTitle = get(data, "datasetName", "");
return {
x: data.categoryLabel ?? -1,
y: data.dataValue ?? -1,
seriesTitle,
rawEventData: data,
} as ChartSelectedDataPoint;
} else {
const data: unknown[] = evt.data as unknown[];
const x: unknown = data[0];
const index = (evt.seriesIndex ?? 0) + 1;
const y: unknown = data[index];
const seriesName =
evt.seriesName && evt.seriesName?.length > 0 ? evt.seriesName : "null";
return {
x: x ?? -1,
y: y ?? -1,
seriesTitle: seriesName,
} as ChartSelectedDataPoint;
}
};
getEChartsOptions = () => {
const options = {
...this.echartsConfigurationBuilder.prepareEChartConfig(
@ -142,22 +171,12 @@ class ChartComponent extends React.Component<
};
dataClickCallback = (params: echarts.ECElementEvent) => {
const eventData: unknown[] = params.data as unknown[];
const x: unknown = eventData[0];
const dataPointClickParams = this.parseOnDataPointClickParams(
params,
this.state.chartType,
);
const index = (params.seriesIndex ?? 0) + 1;
const y: unknown = eventData[index];
const seriesName =
params.seriesName && params.seriesName?.length > 0
? params.seriesName
: "null";
this.props.onDataPointClick({
x: x,
y: y,
seriesTitle: seriesName,
});
this.props.onDataPointClick(dataPointClickParams);
};
initializeEchartsInstance = () => {
@ -304,13 +323,12 @@ class ChartComponent extends React.Component<
height: "100%",
events: {
dataPlotClick: (evt: any) => {
const data = evt.data;
const seriesTitle = get(data, "datasetName", "");
this.props.onDataPointClick({
x: data.categoryLabel,
y: data.dataValue,
seriesTitle,
});
const dataPointClickParams = this.parseOnDataPointClickParams(
evt,
this.state.chartType,
);
this.props.onDataPointClick(dataPointClickParams);
},
},
...this.getCustomFusionChartDataSource(),

View File

@ -32,6 +32,7 @@ export interface ChartSelectedDataPoint {
x: any;
y: any;
seriesTitle: string;
rawEventData?: unknown;
}
export const messages = {