From 87efcc0a0f048ed8eef924c43fa9621b53a443bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andre=CC=81=20Rivet?= Date: Fri, 19 Jun 2020 08:37:34 -0400 Subject: [PATCH 1/5] Resize table on any prop change + testing --- .../components/ControlledTable/index.tsx | 26 +-- tests/selenium/test_sizing.py | 157 +++++++++++++----- 2 files changed, 118 insertions(+), 65 deletions(-) diff --git a/src/dash-table/components/ControlledTable/index.tsx b/src/dash-table/components/ControlledTable/index.tsx index 450cd8643..973be90f6 100644 --- a/src/dash-table/components/ControlledTable/index.tsx +++ b/src/dash-table/components/ControlledTable/index.tsx @@ -150,31 +150,7 @@ export default class ControlledTable extends PureComponent this.updateStylesheet(); this.updateUiViewport(); - const { - style_as_list_view, - style_cell, - style_cell_conditional, - style_data, - style_data_conditional, - style_filter, - style_filter_conditional, - style_header, - style_header_conditional, - style_table - } = this.props; - - this.handleResizeIf( - style_as_list_view, - style_cell, - style_cell_conditional, - style_data, - style_data_conditional, - style_filter, - style_filter_conditional, - style_header, - style_header_conditional, - style_table - ); + this.handleResizeIf(...R.values(this.props)); this.handleDropdown(); this.adjustTooltipPosition(); diff --git a/tests/selenium/test_sizing.py b/tests/selenium/test_sizing.py index 747c4cc69..54df08d25 100644 --- a/tests/selenium/test_sizing.py +++ b/tests/selenium/test_sizing.py @@ -1,9 +1,50 @@ import dash +import pytest + from dash.dependencies import Input, Output from dash.testing import wait from dash_table import DataTable from dash_html_components import Button, Div +base_props = dict( + columns=[ + {"id": "_", "name": ["_", "_", "_"]}, + { + "id": "a", + "name": [ + "A-----------------VERY LONG", + "A-----------------VERY LONG", + "A-----------------VERY LONG", + ], + }, + { + "id": "b", + "name": [ + "A-----------------VERY LONG", + "A-----------------VERY LONG", + "B-----------------VERY LONG", + ], + }, + { + "id": "c", + "name": [ + "A-----------------VERY LONG---", + "B-----------------VERY LONG---------", + "C-----------------VERY LONG------------------", + ], + }, + ], + data=[ + {"_": 0, "a": 85, "b": 601, "c": 891}, + {"_": 0, "a": 967, "b": 189, "c": 514}, + {"_": 0, "a": 398, "b": 262, "c": 743}, + {"_": 0, "a": 89, "b": 560, "c": 582}, + {"_": 0, "a": 809, "b": 591, "c": 511}, + ], + style_table=dict(width=500, minWidth=500, maxWidth=500, paddingBottom=10), + style_cell=dict(width="25%", minWidth="25%", maxWidth="25%"), +) + def cells_are_same_width(target, table): wait.until(lambda: abs(target.size["width"] - table.size["width"]) <= 1, 3) @@ -174,49 +215,10 @@ def update_styles(n_clicks): def test_szng002_percentages_result_in_same_widths(test): - base_props = dict( - columns=[ - {"id": "_", "name": ["_", "_", "_"]}, - { - "id": "a", - "name": [ - "A-----------------VERY LONG", - "A-----------------VERY LONG", - "A-----------------VERY LONG", - ], - }, - { - "id": "b", - "name": [ - "A-----------------VERY LONG", - "A-----------------VERY LONG", - "B-----------------VERY LONG", - ], - }, - { - "id": "c", - "name": [ - "A-----------------VERY LONG---", - "B-----------------VERY LONG---------", - "C-----------------VERY LONG------------------", - ], - }, - ], - data=[ - {"_": 0, "a": 85, "b": 601, "c": 891}, - {"_": 0, "a": 967, "b": 189, "c": 514}, - {"_": 0, "a": 398, "b": 262, "c": 743}, - {"_": 0, "a": 89, "b": 560, "c": 582}, - {"_": 0, "a": 809, "b": 591, "c": 511}, - ], - style_table=dict(width=500, minWidth=500, maxWidth=500, paddingBottom=10), - style_cell=dict(width="25%", minWidth="25%", maxWidth="25%"), - ) + global base_props _fixed_columns = [dict(headers=True, data=1), dict(headers=True)] - _fixed_rows = [dict(headers=True, data=1), dict(headers=True)] - _merge_duplicate_headers = [True, False] variations = [] @@ -248,3 +250,78 @@ def test_szng002_percentages_result_in_same_widths(test): for i in range(1, len(variations)): table = test.driver.find_element_by_css_selector("#table{}".format(i)) cells_are_same_width(target, table) + + +@pytest.mark.parametrize( + "fixed_columns", + [ + dict(), + dict(fixed_columns=dict(headers=True)), + dict(fixed_columns=dict(headers=True, data=1)), + ], +) +@pytest.mark.parametrize( + "fixed_rows", + [ + dict(), + dict(fixed_rows=dict(headers=True)), + dict(fixed_rows=dict(headers=True, data=1)), + ], +) +@pytest.mark.parametrize( + "merge_duplicate_headers", + [dict(merge_duplicate_headers=True), dict(merge_duplicate_headers=False)], +) +@pytest.mark.parametrize( + "callback_props", + [ + dict( + data=[ + {"_": 0, "a": 85, "b": 601, "c": 891}, + {"_": 0, "a": 967, "b": 189, "c": 514}, + {"_": 0, "a": 398, "b": 262, "c": 743}, + { + "_": "SOME VERY LONG VALUE", + "a": "SOME VERY LONG VALUE 2", + "b": "SOME VERY LONG VALUE 3", + "c": "SOME VERY LONG VALUE 4", + }, + {"_": 0, "a": 89, "b": 560, "c": 582}, + {"_": 0, "a": 809, "b": 591, "c": 511}, + ] + ), + dict(merge_duplicate_headers=True), + dict(fixed_rows=dict(headers=True)), + dict(fixed_columns=dict(headers=True)), + dict(fixed_columns=dict(headers=True), fixed_rows=dict(headers=True)), + dict(style_cell=dict(width=200, minWidth=200, maxWidth=200)), + dict(style_table=dict(width=500, minWidth=500, maxWidth=500)), + ], +) +def test_szng003_on_prop_change( + test, fixed_columns, fixed_rows, merge_duplicate_headers, callback_props +): + global base_props + + props = {**base_props, **fixed_columns, **fixed_rows, **merge_duplicate_headers} + + table = DataTable(**props, id="table") + + app = dash.Dash(__name__) + app.layout = Div([Button(id="btn", children=["Update"]), table]) + + @app.callback( + [Output("table", key) for key in callback_props.keys()], + [Input("btn", "n_clicks")], + prevent_initial_call=True, + ) + def callback(n_clicks): + return [callback_props.get(key) for key in callback_props.keys()] + + test.start_server(app) + + target = test.driver.find_element_by_css_selector("#table") + cells_are_same_width(target, target) + + test.driver.find_element_by_css_selector("#btn").click() + cells_are_same_width(target, target) From 8a59c6b28e7334cb062c50f69ee9965667b0c55f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andre=CC=81=20Rivet?= Date: Fri, 19 Jun 2020 08:51:23 -0400 Subject: [PATCH 2/5] handleResize on all prop change except if not fixed --- src/dash-table/components/ControlledTable/index.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/dash-table/components/ControlledTable/index.tsx b/src/dash-table/components/ControlledTable/index.tsx index 973be90f6..4575f2c9e 100644 --- a/src/dash-table/components/ControlledTable/index.tsx +++ b/src/dash-table/components/ControlledTable/index.tsx @@ -150,7 +150,14 @@ export default class ControlledTable extends PureComponent this.updateStylesheet(); this.updateUiViewport(); - this.handleResizeIf(...R.values(this.props)); + const { + fixed_columns, + fixed_rows + } = this.props; + + if (fixed_columns || fixed_rows) { + this.handleResizeIf(...R.values(this.props)); + } this.handleDropdown(); this.adjustTooltipPosition(); From 01c834c0f7f86bfe14e94078e1ce1751678d06de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andre=CC=81=20Rivet?= Date: Fri, 19 Jun 2020 08:59:42 -0400 Subject: [PATCH 3/5] reduce coverage redundency (build is just too long.. and this should still be good enough) --- tests/selenium/test_sizing.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/selenium/test_sizing.py b/tests/selenium/test_sizing.py index 54df08d25..f46bd2fb6 100644 --- a/tests/selenium/test_sizing.py +++ b/tests/selenium/test_sizing.py @@ -255,7 +255,7 @@ def test_szng002_percentages_result_in_same_widths(test): @pytest.mark.parametrize( "fixed_columns", [ - dict(), + # dict(), dict(fixed_columns=dict(headers=True)), dict(fixed_columns=dict(headers=True, data=1)), ], @@ -263,7 +263,7 @@ def test_szng002_percentages_result_in_same_widths(test): @pytest.mark.parametrize( "fixed_rows", [ - dict(), + # dict(), dict(fixed_rows=dict(headers=True)), dict(fixed_rows=dict(headers=True, data=1)), ], @@ -291,8 +291,8 @@ def test_szng002_percentages_result_in_same_widths(test): ] ), dict(merge_duplicate_headers=True), - dict(fixed_rows=dict(headers=True)), - dict(fixed_columns=dict(headers=True)), + # dict(fixed_rows=dict(headers=True)), + # dict(fixed_columns=dict(headers=True)), dict(fixed_columns=dict(headers=True), fixed_rows=dict(headers=True)), dict(style_cell=dict(width=200, minWidth=200, maxWidth=200)), dict(style_table=dict(width=500, minWidth=500, maxWidth=500)), From 3f3cf3334993dca71ec25093a0c123788ddbe956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andre=CC=81=20Rivet?= Date: Fri, 19 Jun 2020 09:26:22 -0400 Subject: [PATCH 4/5] changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64382c92d..98c8412c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] +### Fixed +- [#798](https://github.com/plotly/dash-table/pull/798) Fix a bug where headers are not aligned with columns after an update [#797](https://github.com/plotly/dash-table/issues/797) + ## [4.8.0] - 2020-06-17 ### Added - [#787](https://github.com/plotly/dash-table/pull/787) Add `cell_selectable` property to allow/disallow cell selection @@ -14,7 +18,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - [#785](https://github.com/plotly/dash-table/pull/785) Fix a bug where the table does not refresh correctly if a property was previously missing - [#793](https://github.com/plotly/dash-table/pull/793) - - Fix a bug where headers aren't aligned with columns with fixed_rows [#777](https://github.com/plotly/dash-table/issues/777) + - Fix a bug where headers are not aligned with columns with fixed_rows [#777](https://github.com/plotly/dash-table/issues/777) - Fix a regression where headers don't scroll horizontally with fixed_rows [#780](https://github.com/plotly/dash-table/issues/780) ## [4.7.0] - 2020-05-05 From c93050c95940ba127f784c9a731a4c8ed7ab44e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andre=CC=81=20Rivet?= Date: Fri, 19 Jun 2020 09:51:16 -0400 Subject: [PATCH 5/5] remove `global` --- tests/selenium/test_sizing.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/selenium/test_sizing.py b/tests/selenium/test_sizing.py index f46bd2fb6..d64907eda 100644 --- a/tests/selenium/test_sizing.py +++ b/tests/selenium/test_sizing.py @@ -215,8 +215,6 @@ def update_styles(n_clicks): def test_szng002_percentages_result_in_same_widths(test): - global base_props - _fixed_columns = [dict(headers=True, data=1), dict(headers=True)] _fixed_rows = [dict(headers=True, data=1), dict(headers=True)] _merge_duplicate_headers = [True, False] @@ -301,8 +299,6 @@ def test_szng002_percentages_result_in_same_widths(test): def test_szng003_on_prop_change( test, fixed_columns, fixed_rows, merge_duplicate_headers, callback_props ): - global base_props - props = {**base_props, **fixed_columns, **fixed_rows, **merge_duplicate_headers} table = DataTable(**props, id="table")