diff --git a/@plotly/dash-component-plugins/webpack.config.js b/@plotly/dash-component-plugins/webpack.config.js index 571506812e..85f8207360 100644 --- a/@plotly/dash-component-plugins/webpack.config.js +++ b/@plotly/dash-component-plugins/webpack.config.js @@ -6,8 +6,7 @@ module.exports = { output: { path: path.resolve(__dirname, `./dist`), filename: 'index.js', - library: `dash-component-plugins`, - libraryTarget: 'umd' + library: {name: `dash-component-plugins`, type: 'umd' }, }, externals: { react: { @@ -27,4 +26,4 @@ module.exports = { } ] } -}; \ No newline at end of file +}; diff --git a/@plotly/dash-generator-test-component-nested/webpack.config.js b/@plotly/dash-generator-test-component-nested/webpack.config.js index 3d6e84db46..3fd816d7ef 100644 --- a/@plotly/dash-generator-test-component-nested/webpack.config.js +++ b/@plotly/dash-generator-test-component-nested/webpack.config.js @@ -15,8 +15,10 @@ module.exports = { output: { path: path.resolve(__dirname, dashLibraryName, 'nested'), filename: `${dashLibraryName}.js`, - library: dashLibraryName, - libraryTarget: 'window', + library: { + name: dashLibraryName, + type: 'window', + } }, module: { rules: [ @@ -29,4 +31,4 @@ module.exports = { } ], } -}; \ No newline at end of file +}; diff --git a/@plotly/dash-generator-test-component-standard/webpack.config.js b/@plotly/dash-generator-test-component-standard/webpack.config.js index 391fe37466..2f5325d908 100644 --- a/@plotly/dash-generator-test-component-standard/webpack.config.js +++ b/@plotly/dash-generator-test-component-standard/webpack.config.js @@ -15,8 +15,10 @@ module.exports = { output: { path: path.resolve(__dirname, dashLibraryName), filename: `${dashLibraryName}.js`, - library: dashLibraryName, - libraryTarget: 'window', + library: { + name: dashLibraryName, + type: 'window', + } }, module: { rules: [ @@ -29,4 +31,4 @@ module.exports = { } ], } -}; \ No newline at end of file +}; diff --git a/@plotly/dash-generator-test-component-typescript/webpack.config.js b/@plotly/dash-generator-test-component-typescript/webpack.config.js index da696b0183..6a809b2701 100644 --- a/@plotly/dash-generator-test-component-typescript/webpack.config.js +++ b/@plotly/dash-generator-test-component-typescript/webpack.config.js @@ -10,8 +10,10 @@ module.exports = function (env, argv) { const output = { path: path.resolve(__dirname, dashLibraryName), filename: `${dashLibraryName}.js`, - library: dashLibraryName, - libraryTarget: 'umd', + library: { + name: dashLibraryName, + type: 'umd', + } } const externals = { diff --git a/@plotly/dash-test-components/webpack.config.js b/@plotly/dash-test-components/webpack.config.js index a5c1a36f04..4ca559e2e0 100644 --- a/@plotly/dash-test-components/webpack.config.js +++ b/@plotly/dash-test-components/webpack.config.js @@ -17,8 +17,10 @@ module.exports = { path: path.resolve(__dirname, dashLibraryName), chunkFilename: '[name].js', filename: `${dashLibraryName}.js`, - library: dashLibraryName, - libraryTarget: 'window', + library: { + name: dashLibraryName, + type: 'window', + } }, module: { rules: [ diff --git a/CHANGELOG.md b/CHANGELOG.md index cd196cba51..55e9e0c4b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,17 @@ This project adheres to [Semantic Versioning](https://semver.org/). - [#2508](https://github.com/plotly/dash/pull/2508) Fix error message, when callback output has different length than spec - [#2207](https://github.com/plotly/dash/pull/2207) Fix object of components support. +- [#2500](https://github.com/plotly/dash/pull/2500) Passing customdata by click for scattermapbox, fix [#2493](https://github.com/plotly/dash/issues/2493) - [#2513](https://github.com/plotly/dash/pull/2513) Raise error when iterating over patch objects, fix [#2512](https://github.com/plotly/dash/issues/2512) +## Updated + +- [#2533](https://github.com/plotly/dash/pull/2533) Update Plotly.js to v2.23.1 from v2.20.0. + - Feature release [2.23.0](https://github.com/plotly/plotly.js/releases/tag/v2.23.0) adds legend/colorbar xref/yref. + - Feature release [2.22.0](https://github.com/plotly/plotly.js/releases/tag/v2.22.0) adds `legend` references to traces. + - Feature release [2.21.0](https://github.com/plotly/plotly.js/releases/tag/v2.21.0) adds label.texttemplate to parametric shapes. + - Patch release [2.23.1](https://github.com/plotly/plotly.js/releases/tag/v2.23.1) fix heatmap rendering on iOS and Safari when zsmooth is set to false. + ## [2.9.3] - 2023-04-13 ## Fixed diff --git a/components/dash-core-components/package-lock.json b/components/dash-core-components/package-lock.json index 1ea84718a6..34585785db 100644 --- a/components/dash-core-components/package-lock.json +++ b/components/dash-core-components/package-lock.json @@ -22,7 +22,7 @@ "mathjax": "^3.2.2", "moment": "^2.29.4", "node-polyfill-webpack-plugin": "^2.0.1", - "plotly.js-dist-min": "2.20.0", + "plotly.js-dist-min": "2.23.1", "prop-types": "^15.8.1", "ramda": "^0.28.0", "rc-slider": "^9.7.5", @@ -6578,9 +6578,9 @@ } }, "node_modules/plotly.js-dist-min": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/plotly.js-dist-min/-/plotly.js-dist-min-2.20.0.tgz", - "integrity": "sha512-zhSRwOed3y/cekPWvzOtdc3AVOmHbDpUry5FNITw2IRKkRirRv7SdWvM7YVqqQd4dTsLHKGDuza+3GoR6+45ZQ==" + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/plotly.js-dist-min/-/plotly.js-dist-min-2.23.1.tgz", + "integrity": "sha512-jw8Zo/al2nZAaQtSMTLJeM8I4Ity8UuWDF1oRb0DxMeQdP1ijX76/pKfSNl6T7aTfeHFQwEXxddERuJTL9wvyA==" }, "node_modules/postcss": { "version": "8.4.18", @@ -13969,9 +13969,9 @@ } }, "plotly.js-dist-min": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/plotly.js-dist-min/-/plotly.js-dist-min-2.20.0.tgz", - "integrity": "sha512-zhSRwOed3y/cekPWvzOtdc3AVOmHbDpUry5FNITw2IRKkRirRv7SdWvM7YVqqQd4dTsLHKGDuza+3GoR6+45ZQ==" + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/plotly.js-dist-min/-/plotly.js-dist-min-2.23.1.tgz", + "integrity": "sha512-jw8Zo/al2nZAaQtSMTLJeM8I4Ity8UuWDF1oRb0DxMeQdP1ijX76/pKfSNl6T7aTfeHFQwEXxddERuJTL9wvyA==" }, "postcss": { "version": "8.4.18", diff --git a/components/dash-core-components/package.json b/components/dash-core-components/package.json index d24f8d489d..5ff50c6d29 100644 --- a/components/dash-core-components/package.json +++ b/components/dash-core-components/package.json @@ -49,7 +49,7 @@ "mathjax": "^3.2.2", "moment": "^2.29.4", "node-polyfill-webpack-plugin": "^2.0.1", - "plotly.js-dist-min": "2.20.0", + "plotly.js-dist-min": "2.23.1", "prop-types": "^15.8.1", "ramda": "^0.28.0", "rc-slider": "^9.7.5", diff --git a/components/dash-core-components/src/fragments/Graph.react.js b/components/dash-core-components/src/fragments/Graph.react.js index f669b5ccc2..bed0975b89 100644 --- a/components/dash-core-components/src/fragments/Graph.react.js +++ b/components/dash-core-components/src/fragments/Graph.react.js @@ -87,12 +87,22 @@ const filterEventData = (gd, eventData, event) => { has('customdata', data[pointData.curveNumber]) ) { if (has('pointNumber', fullPoint)) { - pointData.customdata = - data[pointData.curveNumber].customdata[ - fullPoint.pointNumber - ]; + if (typeof fullPoint.pointNumber === 'number') { + pointData.customdata = + data[pointData.curveNumber].customdata[ + fullPoint.pointNumber + ]; + } else if ( + !fullPoint.pointNumber && + fullPoint.data.mode.includes('lines') + ) { + pointData.customdata = + data[pointData.curveNumber].customdata; + } } else if (has('pointNumbers', fullPoint)) { - pointData.customdata = fullPoint.pointNumbers.map(point => { + pointData.customdata = fullPoint.pointNumbers.map(function ( + point + ) { return data[pointData.curveNumber].customdata[point]; }); } diff --git a/components/dash-core-components/tests/integration/dropdown/test_styles.py b/components/dash-core-components/tests/integration/dropdown/test_styles.py index 887b0d3d28..ae07f61c79 100644 --- a/components/dash-core-components/tests/integration/dropdown/test_styles.py +++ b/components/dash-core-components/tests/integration/dropdown/test_styles.py @@ -3,7 +3,10 @@ from dash.html import Div from dash.dash_table import DataTable +from flaky import flaky + +@flaky(max_runs=3) def test_ddst001_cursor_should_be_pointer(dash_duo): app = Dash(__name__) app.layout = Div( diff --git a/components/dash-core-components/tests/integration/graph/test_graph_basics.py b/components/dash-core-components/tests/integration/graph/test_graph_basics.py index 1513a1e59b..5211d3c44d 100644 --- a/components/dash-core-components/tests/integration/graph/test_graph_basics.py +++ b/components/dash-core-components/tests/integration/graph/test_graph_basics.py @@ -321,3 +321,51 @@ def set_data(dataset): assert dash_dcc.wait_for_text_to_equal( "#relayout-data", "[0, -1, -2]" ), "graph data must contain frame [0,-1,-2]" + + +def test_grbs007_graph_scatter_lines_customdata(dash_dcc): + app = Dash(__name__) + + expected_value = "obj-1" + + scatter_figures = go.Figure( + data=[ + go.Scatter( + x=[0, 1, 1, 0, 0], + y=[1, 1, 2, 2, 1], + mode="lines", + fill="toself", + customdata=[expected_value], + ) + ] + ) + + app.layout = html.Div( + [ + dcc.Graph( + id="scatter-lines", + figure=scatter_figures, + style={"width": 600, "height": 300}, + ), + dcc.Textarea(id="test-text-area"), + ], + style={"width": 1000, "height": 500}, + ) + + @app.callback( + Output("test-text-area", "value"), Input("scatter-lines", "clickData") + ) + def handleClick(clickData): + return json.dumps(clickData) + + dash_dcc.start_server(app) + dash_dcc.wait_for_element("#scatter-lines") + + dash_dcc.find_elements("g .xy")[0].click() + + data = dash_dcc.wait_for_element("#test-text-area").get_attribute("value") + assert data != "", "graph clickData must contain data" + + data = json.loads(data) + assert "customdata" in data["points"][0], "graph clickData must contain customdata" + assert data["points"][0]["customdata"][0] == expected_value diff --git a/components/dash-core-components/webpack.config.js b/components/dash-core-components/webpack.config.js index 468db47087..1a26381666 100644 --- a/components/dash-core-components/webpack.config.js +++ b/components/dash-core-components/webpack.config.js @@ -49,8 +49,10 @@ module.exports = (env, argv) => { path: path.resolve(__dirname, dashLibraryName), chunkFilename: '[name].js', filename, - library: dashLibraryName, - libraryTarget: 'window', + library: { + name: dashLibraryName, + type: 'window', + } }, externals, module: { diff --git a/components/dash-html-components/tests/test_integration.py b/components/dash-html-components/tests/test_integration.py index 648c869df5..d0551d6e90 100644 --- a/components/dash-html-components/tests/test_integration.py +++ b/components/dash-html-components/tests/test_integration.py @@ -113,8 +113,12 @@ def test_click_static(dash_duo): [ html.Div("no event listener", className="div-1"), html.Div("event listener", id="div-2", n_clicks=0), - html.Div("no event listener", id="div-3", n_clicks=0, disable_n_clicks=True), - html.Div("event listener", id="div-4", n_clicks=0, disable_n_clicks=False), + html.Div( + "no event listener", id="div-3", n_clicks=0, disable_n_clicks=True + ), + html.Div( + "event listener", id="div-4", n_clicks=0, disable_n_clicks=False + ), html.Div(id="div-output"), ] ) diff --git a/components/dash-html-components/webpack.config.js b/components/dash-html-components/webpack.config.js index 5cafc8ddfe..c557bd6852 100644 --- a/components/dash-html-components/webpack.config.js +++ b/components/dash-html-components/webpack.config.js @@ -46,8 +46,10 @@ module.exports = (env, argv) => { output: { path: path.resolve(__dirname, dashLibraryName), filename, - library: dashLibraryName, - libraryTarget: 'window', + library: { + name: dashLibraryName, + type: 'window', + } }, externals, module: { diff --git a/components/dash-table/.config/webpack/base.js b/components/dash-table/.config/webpack/base.js index 2820c161cd..a7be934a2d 100644 --- a/components/dash-table/.config/webpack/base.js +++ b/components/dash-table/.config/webpack/base.js @@ -26,8 +26,10 @@ module.exports = (options = {}) => { output: { path: path.resolve(__dirname, `./../../${dashLibraryName}`), filename: '[name].js', - library: dashLibraryName, - libraryTarget: 'window' + library: { + name: dashLibraryName, + type: 'window', + } }, devtool: 'source-map', externals: { diff --git a/dash/_get_paths.py b/dash/_get_paths.py index 57ec9d875e..f439511b0b 100644 --- a/dash/_get_paths.py +++ b/dash/_get_paths.py @@ -34,11 +34,11 @@ def get_relative_path(path): When working locally, `requests_pathname_prefix` might be unset and so a relative URL like `/page-2` can just be `/page-2`. However, when the app is deployed to a URL like `/my-dash-app`, then - `app.get_relative_path('/page-2')` will return `/my-dash-app/page-2`. + `dash.get_relative_path('/page-2')` will return `/my-dash-app/page-2`. This can be used as an alternative to `get_asset_url` as well with - `app.get_relative_path('/assets/logo.png')` + `dash.get_relative_path('/assets/logo.png')` - Use this function with `app.strip_relative_path` in callbacks that + Use this function with `dash.strip_relative_path` in callbacks that deal with `dcc.Location` `pathname` routing. That is, your usage may look like: ``` @@ -46,13 +46,13 @@ def get_relative_path(path): dcc.Location(id='url'), html.Div(id='content') ]) - @app.callback(Output('content', 'children'), [Input('url', 'pathname')]) + @dash.callback(Output('content', 'children'), [Input('url', 'pathname')]) def display_content(path): - page_name = app.strip_relative_path(path) + page_name = dash.strip_relative_path(path) if not page_name: # None or '' return html.Div([ - dcc.Link(href=app.get_relative_path('/page-1')), - dcc.Link(href=app.get_relative_path('/page-2')), + dcc.Link(href=dash.get_relative_path('/page-1')), + dcc.Link(href=dash.get_relative_path('/page-2')), ]) elif page_name == 'page-1': return chapters.page_1 @@ -90,13 +90,13 @@ def strip_relative_path(path): dcc.Location(id='url'), html.Div(id='content') ]) - @app.callback(Output('content', 'children'), [Input('url', 'pathname')]) + @dash.callback(Output('content', 'children'), [Input('url', 'pathname')]) def display_content(path): - page_name = app.strip_relative_path(path) + page_name = dash.strip_relative_path(path) if not page_name: # None or '' return html.Div([ - dcc.Link(href=app.get_relative_path('/page-1')), - dcc.Link(href=app.get_relative_path('/page-2')), + dcc.Link(href=dash.get_relative_path('/page-1')), + dcc.Link(href=dash.get_relative_path('/page-2')), ]) elif page_name == 'page-1': return chapters.page_1 @@ -113,15 +113,15 @@ def display_content(path): When working locally, `requests_pathname_prefix` might be unset and so a relative URL like `/page-2` can just be `/page-2`. However, when the app is deployed to a URL like `/my-dash-app`, then - `app.get_relative_path('/page-2')` will return `/my-dash-app/page-2` + `dash.get_relative_path('/page-2')` will return `/my-dash-app/page-2` The `pathname` property of `dcc.Location` will return '`/my-dash-app/page-2`' to the callback. - In this case, `app.strip_relative_path('/my-dash-app/page-2')` + In this case, `dash.strip_relative_path('/my-dash-app/page-2')` will return `'page-2'` For nested URLs, slashes are still included: - `app.strip_relative_path('/page-1/sub-page-1/')` will return + `dash.strip_relative_path('/page-1/sub-page-1/')` will return `page-1/sub-page-1` ``` """ diff --git a/dash/dash-renderer/webpack.base.config.js b/dash/dash-renderer/webpack.base.config.js index 12c1cc6f5b..bdfe6e3041 100644 --- a/dash/dash-renderer/webpack.base.config.js +++ b/dash/dash-renderer/webpack.base.config.js @@ -56,8 +56,10 @@ const rendererOptions = { output: { path: path.resolve(__dirname, "build"), filename: `${dashLibraryName}.dev.js`, - library: dashLibraryName, - libraryTarget: 'window', + library: { + name: dashLibraryName, + type: 'window', + } }, externals: { react: 'React', @@ -84,8 +86,10 @@ module.exports = options => [ output: { path: path.resolve(__dirname, "build"), filename: `${dashLibraryName}.min.js`, - library: dashLibraryName, - libraryTarget: 'window', + library: { + name: dashLibraryName, + type: 'window', + } }, plugins: R.concat( options.plugins || [], diff --git a/tests/integration/renderer/test_request_hooks.py b/tests/integration/renderer/test_request_hooks.py index 9b1e57f56f..ea2bede020 100644 --- a/tests/integration/renderer/test_request_hooks.py +++ b/tests/integration/renderer/test_request_hooks.py @@ -253,10 +253,7 @@ def wrap(*args, **kwargs): try: if flask.request.method == "OPTIONS": return func(*args, **kwargs) - token = ( - flask.request.authorization - or flask.request.headers.environ.get("HTTP_AUTHORIZATION") - ) + token = flask.request.headers.environ.get("HTTP_AUTHORIZATION") if required_jwt_len and ( not token or len(token) != required_jwt_len + len("Bearer ") ):