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:
parent
be4a43408c
commit
b53bc72f92
|
|
@ -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"]}}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
84
app/client/cypress/fixtures/chartCustomSankeyDataDsl.json
Normal file
84
app/client/cypress/fixtures/chartCustomSankeyDataDsl.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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} />);
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export interface ChartSelectedDataPoint {
|
|||
x: any;
|
||||
y: any;
|
||||
seriesTitle: string;
|
||||
rawEventData?: unknown;
|
||||
}
|
||||
|
||||
export const messages = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user