From d2d0f1a74689835d4c96b29a02f8144c94600043 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Tue, 25 Aug 2020 11:50:04 -0400 Subject: [PATCH 01/20] add persistenceTransforms for datePickerSingle to strip time --- src/components/DatePickerSingle.react.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/components/DatePickerSingle.react.js b/src/components/DatePickerSingle.react.js index 3391e430f..629a1a151 100644 --- a/src/components/DatePickerSingle.react.js +++ b/src/components/DatePickerSingle.react.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React, {Component, lazy, Suspense} from 'react'; import datePickerSingle from '../utils/LazyLoader/datePickerSingle'; +import moment from 'moment'; const RealDateSingleRange = lazy(datePickerSingle); @@ -220,6 +221,20 @@ DatePickerSingle.propTypes = { persistence_type: PropTypes.oneOf(['local', 'session', 'memory']), }; +DatePickerSingle.persistenceTransforms = { + date: { + extract: propValue => { + if (!(propValue === null || propValue === undefined)) { + return moment(propValue) + .startOf('day') + .format('YYYY-MM-DD'); + } + return propValue; + }, + apply: storedValue => storedValue, + }, +}; + DatePickerSingle.defaultProps = { calendar_orientation: 'horizontal', is_RTL: false, From 4d18af38e922a157c20d8d888895800497234b28 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Tue, 25 Aug 2020 11:50:45 -0400 Subject: [PATCH 02/20] add persistenceTransforms for datePickerRange to strip time --- src/components/DatePickerRange.react.js | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/components/DatePickerRange.react.js b/src/components/DatePickerRange.react.js index 58560c6c9..301302984 100644 --- a/src/components/DatePickerRange.react.js +++ b/src/components/DatePickerRange.react.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React, {Component, lazy, Suspense} from 'react'; import datePickerRange from '../utils/LazyLoader/datePickerRange'; +import moment from 'moment'; const RealDatePickerRange = lazy(datePickerRange); @@ -263,6 +264,31 @@ DatePickerRange.propTypes = { persistence_type: PropTypes.oneOf(['local', 'session', 'memory']), }; +DatePickerRange.persistenceTransforms = { + end_date: { + extract: propValue => { + if (!(propValue === null || propValue === undefined)) { + return moment(propValue) + .startOf('day') + .format('YYYY-MM-DD'); + } + return propValue; + }, + apply: storedValue => storedValue, + }, + start_date: { + extract: propValue => { + if (!(propValue === null || propValue === undefined)) { + return moment(propValue) + .startOf('day') + .format('YYYY-MM-DD'); + } + return propValue; + }, + apply: storedValue => storedValue, + }, +}; + DatePickerRange.defaultProps = { calendar_orientation: 'horizontal', is_RTL: false, From 1c61fa40d5c26b2e6e00c9f15d49aa32979b29c2 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Tue, 25 Aug 2020 11:51:20 -0400 Subject: [PATCH 03/20] circleci pointing to dash branch --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 31961700a..b94c555b7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -80,7 +80,7 @@ jobs: command: | . venv/bin/activate && mkdir packages # build main dash - git clone --depth 1 https://github.com/plotly/dash.git dash-main + git clone -b persistence-hg --depth 1 https://github.com/plotly/dash.git dash-main cd dash-main && pip install -e .[dev] --progress-bar off && python setup.py sdist && mv dist/* ../packages/ cd dash-renderer && npm ci && npm run build python setup.py sdist && mv dist/* ../../packages/ && cd ../.. From de4647a7443dd63558438976e02df1e14e1d94f1 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Tue, 25 Aug 2020 12:27:00 -0400 Subject: [PATCH 04/20] noise From cc69b07462f3a561cb7926558a29f6fb53875710 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Tue, 25 Aug 2020 12:31:44 -0400 Subject: [PATCH 05/20] noise From f4b82d16eeb907476e9ef5d6e35f11083c155c7b Mon Sep 17 00:00:00 2001 From: harrisonn Date: Thu, 27 Aug 2020 15:39:48 -0400 Subject: [PATCH 06/20] add tests for persistence in date picker single and range --- .../calendar/test_date_picker_persistence.py | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 tests/integration/calendar/test_date_picker_persistence.py diff --git a/tests/integration/calendar/test_date_picker_persistence.py b/tests/integration/calendar/test_date_picker_persistence.py new file mode 100644 index 000000000..a640ce3ed --- /dev/null +++ b/tests/integration/calendar/test_date_picker_persistence.py @@ -0,0 +1,167 @@ +from datetime import datetime, timedelta + +import pytest +import dash +import dash_html_components as html +import dash_core_components as dcc +from dash.dependencies import Input, Output + +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.common.action_chains import ActionChains + + +def test_rdpr001_persisted_dps(dash_dcc): + def send_date_dps(target, date): + ( + ActionChains(dash_dcc.driver) + .move_to_element(target) + .pause(0.2) + .click(target) + .send_keys(Keys.END) + .key_down(Keys.SHIFT) + .send_keys(Keys.HOME) + .key_up(Keys.SHIFT) + .send_keys(Keys.DELETE) + .send_keys(str(date)) + .send_keys(Keys.ENTER) + ).perform() + + app = dash.Dash(__name__) + app.layout = html.Div( + [ + html.Button("fire callback", id="btn"), + html.Div( + children=[ + dcc.DatePickerSingle( + id="dps1", + date=datetime.today(), + persistence=True, + persistence_type="session", + ), + html.P("dps1", id="dps1-p"), + html.Div(id="container"), + html.P("dps2", id="dps2-p"), + ] + ), + ] + ) + + @app.callback(Output("container", "children"), [Input("btn", "n_clicks")]) + def update_output(value): + return dcc.DatePickerSingle( + id="dps2", + date=datetime.today(), + persistence=True, + persistence_type="session", + ) + + @app.callback(Output("dps1-p", "children"), [Input("dps1", "date")]) + def display_dps1(value): + return value + + @app.callback(Output("dps2-p", "children"), [Input("dps2", "date")]) + def display_dps2(value): + return value + + dash_dcc.start_server(app) + dps1 = dash_dcc.find_element("#dps1") + dps2 = dash_dcc.find_element("#dps2") + + send_date_dps(dps1, "01/01/2020") + dash_dcc.wait_for_text_to_equal("#dps1-p", "2020-01-01") + + send_date_dps(dps2, "01/01/2020") + dash_dcc.wait_for_text_to_equal("#dps2-p", "2020-01-01") + + dash_dcc.find_element("#btn").click() + + dash_dcc.wait_for_text_to_equal("#dps1-p", "2020-01-01") + dash_dcc.wait_for_text_to_equal("#dps2-p", "2020-01-01") + + +def test_rdpr002_persisted_dpr(dash_dcc): + def send_date_dpr(target, start_date, end_date): + ( + ActionChains(dash_dcc.driver) + .move_to_element(target) + .click(target) + .send_keys(Keys.END) + .key_down(Keys.SHIFT) + .send_keys(Keys.HOME) + .key_up(Keys.SHIFT) + .send_keys(str(start_date)) + .pause(0.2) + .send_keys(Keys.END) + .key_down(Keys.SHIFT) + .send_keys(Keys.HOME) + .key_up(Keys.SHIFT) + .send_keys(str(end_date)) + ).perform() + + app = dash.Dash(__name__) + app.layout = html.Div( + [ + html.Button("fire callback", id="btn"), + html.Div( + children=[ + dcc.DatePickerRange( + id="dpr1", + start_date=datetime.today() - timedelta(days=3), + end_date=datetime.today(), + persistence=True, + persistence_type="session", + ), + html.P("dpr1", id="dpr1-p-start"), + html.P("dpr1", id="dpr1-p-end"), + html.Div(id="container"), + html.P("dpr2", id="dpr2-p-start"), + html.P("dpr2", id="dpr2-p-end"), + ] + ), + ] + ) + + @app.callback(Output("container", "children"), [Input("btn", "n_clicks")]) + def update_output(value): + return dcc.DatePickerRange( + id="dpr2", + start_date=datetime.today() - timedelta(days=3), + end_date=datetime.today(), + persistence=True, + persistence_type="session", + ) + + @app.callback(Output("dpr1-p-start", "children"), [Input("dpr1", "start_date")]) + def display_dps1(value): + return value + + @app.callback(Output("dpr1-p-end", "children"), [Input("dpr1", "end_date")]) + def display_dps1(value): + return value + + @app.callback(Output("dpr2-p-start", "children"), [Input("dpr2", "start_date")]) + def display_dps2(value): + return value + + @app.callback(Output("dpr2-p-end", "children"), [Input("dpr2", "end_date")]) + def display_dps2(value): + return value + + dash_dcc.start_server(app) + dpr1 = dash_dcc.find_element("div#dpr1 div div div div .DateInput_input") + dpr2 = dash_dcc.find_element("div#dpr2 div div div div .DateInput_input") + + send_date_dpr(dpr1, "01/01/2020", "01/02/2020") + dash_dcc.wait_for_text_to_equal("#dpr1-p-start", "2020-01-01") + dash_dcc.wait_for_text_to_equal("#dpr1-p-end", "2020-01-02") + + send_date_dpr(dpr2, "01/01/2020", "01/02/2020") + dash_dcc.wait_for_text_to_equal("#dpr2-p-start", "2020-01-01") + dash_dcc.wait_for_text_to_equal("#dpr2-p-end", "2020-01-02") + + dash_dcc.find_element("#btn").click() + + dash_dcc.wait_for_text_to_equal("#dpr1-p-start", "2020-01-01") + dash_dcc.wait_for_text_to_equal("#dpr1-p-end", "2020-01-02") + dash_dcc.wait_for_text_to_equal("#dpr2-p-start", "2020-01-01") + dash_dcc.wait_for_text_to_equal("#dpr2-p-end", "2020-01-02") From c66bb74b41bf425cd6785158d0a9a435e7ec2fec Mon Sep 17 00:00:00 2001 From: harrisonn Date: Tue, 1 Sep 2020 11:50:47 -0400 Subject: [PATCH 07/20] rm obsolete import --- tests/integration/calendar/test_date_picker_persistence.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration/calendar/test_date_picker_persistence.py b/tests/integration/calendar/test_date_picker_persistence.py index a640ce3ed..b7cafcb20 100644 --- a/tests/integration/calendar/test_date_picker_persistence.py +++ b/tests/integration/calendar/test_date_picker_persistence.py @@ -1,6 +1,5 @@ from datetime import datetime, timedelta -import pytest import dash import dash_html_components as html import dash_core_components as dcc From 27458552aee2c0ac875d646733408181f6bf394b Mon Sep 17 00:00:00 2001 From: harrisonn Date: Tue, 1 Sep 2020 18:05:28 -0400 Subject: [PATCH 08/20] noise From 24db1fec6048564be7cdd98fb05f047f3b4408f8 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Wed, 2 Sep 2020 14:59:39 -0400 Subject: [PATCH 09/20] noise From 57e50198621c1220ba4a56e3a5943418ddc9ba79 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Thu, 3 Sep 2020 09:02:21 -0400 Subject: [PATCH 10/20] use ramda isNil --- src/components/DatePickerRange.react.js | 5 +++-- src/components/DatePickerSingle.react.js | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/DatePickerRange.react.js b/src/components/DatePickerRange.react.js index 301302984..05e37b9a7 100644 --- a/src/components/DatePickerRange.react.js +++ b/src/components/DatePickerRange.react.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React, {Component, lazy, Suspense} from 'react'; import datePickerRange from '../utils/LazyLoader/datePickerRange'; import moment from 'moment'; +import {isNil} from 'ramda'; const RealDatePickerRange = lazy(datePickerRange); @@ -267,7 +268,7 @@ DatePickerRange.propTypes = { DatePickerRange.persistenceTransforms = { end_date: { extract: propValue => { - if (!(propValue === null || propValue === undefined)) { + if (!isNil(propValue)) { return moment(propValue) .startOf('day') .format('YYYY-MM-DD'); @@ -278,7 +279,7 @@ DatePickerRange.persistenceTransforms = { }, start_date: { extract: propValue => { - if (!(propValue === null || propValue === undefined)) { + if (!isNil(propValue)) { return moment(propValue) .startOf('day') .format('YYYY-MM-DD'); diff --git a/src/components/DatePickerSingle.react.js b/src/components/DatePickerSingle.react.js index 629a1a151..431e14651 100644 --- a/src/components/DatePickerSingle.react.js +++ b/src/components/DatePickerSingle.react.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React, {Component, lazy, Suspense} from 'react'; import datePickerSingle from '../utils/LazyLoader/datePickerSingle'; import moment from 'moment'; +import {isNil} from 'ramda'; const RealDateSingleRange = lazy(datePickerSingle); @@ -224,7 +225,7 @@ DatePickerSingle.propTypes = { DatePickerSingle.persistenceTransforms = { date: { extract: propValue => { - if (!(propValue === null || propValue === undefined)) { + if (!isNil(propValue)) { return moment(propValue) .startOf('day') .format('YYYY-MM-DD'); From c2668a20cb82117b113a6cd4dafcf6fb3ac81f28 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Thu, 3 Sep 2020 12:57:31 -0400 Subject: [PATCH 11/20] simplify dps test --- .../calendar/test_date_picker_persistence.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/tests/integration/calendar/test_date_picker_persistence.py b/tests/integration/calendar/test_date_picker_persistence.py index b7cafcb20..babede8cf 100644 --- a/tests/integration/calendar/test_date_picker_persistence.py +++ b/tests/integration/calendar/test_date_picker_persistence.py @@ -12,17 +12,7 @@ def test_rdpr001_persisted_dps(dash_dcc): def send_date_dps(target, date): ( - ActionChains(dash_dcc.driver) - .move_to_element(target) - .pause(0.2) - .click(target) - .send_keys(Keys.END) - .key_down(Keys.SHIFT) - .send_keys(Keys.HOME) - .key_up(Keys.SHIFT) - .send_keys(Keys.DELETE) - .send_keys(str(date)) - .send_keys(Keys.ENTER) + ActionChains(dash_dcc.driver).send_keys(str(date)).send_keys(Keys.ENTER) ).perform() app = dash.Dash(__name__) @@ -66,9 +56,11 @@ def display_dps2(value): dps1 = dash_dcc.find_element("#dps1") dps2 = dash_dcc.find_element("#dps2") + dash_dcc.clear_input(dps1) send_date_dps(dps1, "01/01/2020") dash_dcc.wait_for_text_to_equal("#dps1-p", "2020-01-01") + dash_dcc.clear_input(dps2) send_date_dps(dps2, "01/01/2020") dash_dcc.wait_for_text_to_equal("#dps2-p", "2020-01-01") From c76c973093f84d1a3411b530875768c3efffbe80 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Thu, 3 Sep 2020 14:58:32 -0400 Subject: [PATCH 12/20] noise From 605594c289e5c62c617fe521cfacf79baaccf618 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Thu, 3 Sep 2020 16:15:59 -0400 Subject: [PATCH 13/20] simplify tests for dps and dpr using dash_dcc functions --- .../calendar/test_date_picker_persistence.py | 135 ++++-------------- 1 file changed, 31 insertions(+), 104 deletions(-) diff --git a/tests/integration/calendar/test_date_picker_persistence.py b/tests/integration/calendar/test_date_picker_persistence.py index babede8cf..a074da16f 100644 --- a/tests/integration/calendar/test_date_picker_persistence.py +++ b/tests/integration/calendar/test_date_picker_persistence.py @@ -1,112 +1,54 @@ -from datetime import datetime, timedelta +from datetime import datetime import dash import dash_html_components as html import dash_core_components as dcc from dash.dependencies import Input, Output -from selenium.webdriver.common.keys import Keys -from selenium.webdriver.common.action_chains import ActionChains - - -def test_rdpr001_persisted_dps(dash_dcc): - def send_date_dps(target, date): - ( - ActionChains(dash_dcc.driver).send_keys(str(date)).send_keys(Keys.ENTER) - ).perform() +def test_rdpr003_persisted_dps(dash_dcc): app = dash.Dash(__name__) app.layout = html.Div( [ - html.Button("fire callback", id="btn"), - html.Div( - children=[ - dcc.DatePickerSingle( - id="dps1", - date=datetime.today(), - persistence=True, - persistence_type="session", - ), - html.P("dps1", id="dps1-p"), - html.Div(id="container"), - html.P("dps2", id="dps2-p"), - ] - ), + html.Button("fire callback", id="btn", n_clicks=1), + html.Div(children=[html.Div(id="container"), html.P("dps", id="dps-p"),]), ] ) @app.callback(Output("container", "children"), [Input("btn", "n_clicks")]) def update_output(value): return dcc.DatePickerSingle( - id="dps2", - date=datetime.today(), + id="dps", + min_date_allowed=datetime(2020, 1, 1), + max_date_allowed=datetime(2020, 1, 7), + date=datetime(2020, 1, 3, 1, 1, 1, value), persistence=True, persistence_type="session", ) - @app.callback(Output("dps1-p", "children"), [Input("dps1", "date")]) - def display_dps1(value): - return value - - @app.callback(Output("dps2-p", "children"), [Input("dps2", "date")]) - def display_dps2(value): + @app.callback(Output("dps-p", "children"), [Input("dps", "date")]) + def display_dps(value): return value dash_dcc.start_server(app) - dps1 = dash_dcc.find_element("#dps1") - dps2 = dash_dcc.find_element("#dps2") - - dash_dcc.clear_input(dps1) - send_date_dps(dps1, "01/01/2020") - dash_dcc.wait_for_text_to_equal("#dps1-p", "2020-01-01") - dash_dcc.clear_input(dps2) - send_date_dps(dps2, "01/01/2020") - dash_dcc.wait_for_text_to_equal("#dps2-p", "2020-01-01") + dash_dcc.select_date_single("dps", day="2") + dash_dcc.wait_for_text_to_equal("#dps-p", "2020-01-02") dash_dcc.find_element("#btn").click() + dash_dcc.wait_for_text_to_equal("#dps-p", "2020-01-02") - dash_dcc.wait_for_text_to_equal("#dps1-p", "2020-01-01") - dash_dcc.wait_for_text_to_equal("#dps2-p", "2020-01-01") - - -def test_rdpr002_persisted_dpr(dash_dcc): - def send_date_dpr(target, start_date, end_date): - ( - ActionChains(dash_dcc.driver) - .move_to_element(target) - .click(target) - .send_keys(Keys.END) - .key_down(Keys.SHIFT) - .send_keys(Keys.HOME) - .key_up(Keys.SHIFT) - .send_keys(str(start_date)) - .pause(0.2) - .send_keys(Keys.END) - .key_down(Keys.SHIFT) - .send_keys(Keys.HOME) - .key_up(Keys.SHIFT) - .send_keys(str(end_date)) - ).perform() +def test_rdpr004_persisted_dpr(dash_dcc): app = dash.Dash(__name__) app.layout = html.Div( [ - html.Button("fire callback", id="btn"), + html.Button("fire callback", id="btn", n_clicks=1), html.Div( children=[ - dcc.DatePickerRange( - id="dpr1", - start_date=datetime.today() - timedelta(days=3), - end_date=datetime.today(), - persistence=True, - persistence_type="session", - ), - html.P("dpr1", id="dpr1-p-start"), - html.P("dpr1", id="dpr1-p-end"), html.Div(id="container"), - html.P("dpr2", id="dpr2-p-start"), - html.P("dpr2", id="dpr2-p-end"), + html.P("dpr", id="dpr-p-start"), + html.P("dpr", id="dpr-p-end"), ] ), ] @@ -115,44 +57,29 @@ def send_date_dpr(target, start_date, end_date): @app.callback(Output("container", "children"), [Input("btn", "n_clicks")]) def update_output(value): return dcc.DatePickerRange( - id="dpr2", - start_date=datetime.today() - timedelta(days=3), - end_date=datetime.today(), + id="dpr", + min_date_allowed=datetime(2020, 1, 1), + max_date_allowed=datetime(2020, 1, 7), + start_date=datetime(2020, 1, 3, 1, 1, 1, value), + end_date=datetime(2020, 1, 4, 1, 1, 1, value), persistence=True, persistence_type="session", ) - @app.callback(Output("dpr1-p-start", "children"), [Input("dpr1", "start_date")]) - def display_dps1(value): - return value - - @app.callback(Output("dpr1-p-end", "children"), [Input("dpr1", "end_date")]) - def display_dps1(value): + @app.callback(Output("dpr-p-start", "children"), [Input("dpr", "start_date")]) + def display_dpr_start(value): return value - @app.callback(Output("dpr2-p-start", "children"), [Input("dpr2", "start_date")]) - def display_dps2(value): - return value - - @app.callback(Output("dpr2-p-end", "children"), [Input("dpr2", "end_date")]) - def display_dps2(value): + @app.callback(Output("dpr-p-end", "children"), [Input("dpr", "end_date")]) + def display_dpr_end(value): return value dash_dcc.start_server(app) - dpr1 = dash_dcc.find_element("div#dpr1 div div div div .DateInput_input") - dpr2 = dash_dcc.find_element("div#dpr2 div div div div .DateInput_input") - send_date_dpr(dpr1, "01/01/2020", "01/02/2020") - dash_dcc.wait_for_text_to_equal("#dpr1-p-start", "2020-01-01") - dash_dcc.wait_for_text_to_equal("#dpr1-p-end", "2020-01-02") - - send_date_dpr(dpr2, "01/01/2020", "01/02/2020") - dash_dcc.wait_for_text_to_equal("#dpr2-p-start", "2020-01-01") - dash_dcc.wait_for_text_to_equal("#dpr2-p-end", "2020-01-02") + dash_dcc.select_date_range("dpr", (2, 5)) + dash_dcc.wait_for_text_to_equal("#dpr-p-start", "2020-01-02") + dash_dcc.wait_for_text_to_equal("#dpr-p-end", "2020-01-05") dash_dcc.find_element("#btn").click() - - dash_dcc.wait_for_text_to_equal("#dpr1-p-start", "2020-01-01") - dash_dcc.wait_for_text_to_equal("#dpr1-p-end", "2020-01-02") - dash_dcc.wait_for_text_to_equal("#dpr2-p-start", "2020-01-01") - dash_dcc.wait_for_text_to_equal("#dpr2-p-end", "2020-01-02") + dash_dcc.wait_for_text_to_equal("#dpr-p-start", "2020-01-02") + dash_dcc.wait_for_text_to_equal("#dpr-p-end", "2020-01-05") From 4ba16c8c7b71b80b95ea3c3572b65c82b04e18b3 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Thu, 3 Sep 2020 16:19:50 -0400 Subject: [PATCH 14/20] change function names and add comment --- .../calendar/test_date_picker_persistence.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/integration/calendar/test_date_picker_persistence.py b/tests/integration/calendar/test_date_picker_persistence.py index a074da16f..4d3cb9c80 100644 --- a/tests/integration/calendar/test_date_picker_persistence.py +++ b/tests/integration/calendar/test_date_picker_persistence.py @@ -6,7 +6,7 @@ from dash.dependencies import Input, Output -def test_rdpr003_persisted_dps(dash_dcc): +def test_rdpr001_persisted_dps(dash_dcc): app = dash.Dash(__name__) app.layout = html.Div( [ @@ -15,6 +15,8 @@ def test_rdpr003_persisted_dps(dash_dcc): ] ) + # changing value of date with each callback to verify + # persistenceTransforms is stripping the time-part from the date-time @app.callback(Output("container", "children"), [Input("btn", "n_clicks")]) def update_output(value): return dcc.DatePickerSingle( @@ -33,13 +35,12 @@ def display_dps(value): dash_dcc.start_server(app) dash_dcc.select_date_single("dps", day="2") - dash_dcc.wait_for_text_to_equal("#dps-p", "2020-01-02") dash_dcc.find_element("#btn").click() dash_dcc.wait_for_text_to_equal("#dps-p", "2020-01-02") -def test_rdpr004_persisted_dpr(dash_dcc): +def test_rdpr002_persisted_dpr(dash_dcc): app = dash.Dash(__name__) app.layout = html.Div( [ @@ -54,6 +55,8 @@ def test_rdpr004_persisted_dpr(dash_dcc): ] ) + # changing value of start_date and end_date with each callback to verify + # persistenceTransforms is stripping the time-part from the date-time @app.callback(Output("container", "children"), [Input("btn", "n_clicks")]) def update_output(value): return dcc.DatePickerRange( @@ -77,7 +80,6 @@ def display_dpr_end(value): dash_dcc.start_server(app) dash_dcc.select_date_range("dpr", (2, 5)) - dash_dcc.wait_for_text_to_equal("#dpr-p-start", "2020-01-02") dash_dcc.wait_for_text_to_equal("#dpr-p-end", "2020-01-05") dash_dcc.find_element("#btn").click() From cc121c615b7a19144485fca904bd187d175dd3c1 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Thu, 3 Sep 2020 16:35:19 -0400 Subject: [PATCH 15/20] removing comma --- tests/integration/calendar/test_date_picker_persistence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/calendar/test_date_picker_persistence.py b/tests/integration/calendar/test_date_picker_persistence.py index 4d3cb9c80..f05d8847c 100644 --- a/tests/integration/calendar/test_date_picker_persistence.py +++ b/tests/integration/calendar/test_date_picker_persistence.py @@ -11,7 +11,7 @@ def test_rdpr001_persisted_dps(dash_dcc): app.layout = html.Div( [ html.Button("fire callback", id="btn", n_clicks=1), - html.Div(children=[html.Div(id="container"), html.P("dps", id="dps-p"),]), + html.Div(children=[html.Div(id="container"), html.P("dps", id="dps-p")]), ] ) From 32852c074683e2c1fffc01973db2f2dbbcc8579c Mon Sep 17 00:00:00 2001 From: harrisonn Date: Fri, 4 Sep 2020 14:26:39 -0400 Subject: [PATCH 16/20] add DatePickerPersistence for shared logic between dps and dpr --- src/components/DatePickerRange.react.js | 29 ++++-------------------- src/components/DatePickerSingle.react.js | 15 ++---------- src/utils/DatePickerPersistence.js | 14 ++++++++++++ 3 files changed, 21 insertions(+), 37 deletions(-) create mode 100644 src/utils/DatePickerPersistence.js diff --git a/src/components/DatePickerRange.react.js b/src/components/DatePickerRange.react.js index 05e37b9a7..be243120e 100644 --- a/src/components/DatePickerRange.react.js +++ b/src/components/DatePickerRange.react.js @@ -1,10 +1,11 @@ import PropTypes from 'prop-types'; import React, {Component, lazy, Suspense} from 'react'; import datePickerRange from '../utils/LazyLoader/datePickerRange'; -import moment from 'moment'; -import {isNil} from 'ramda'; +import transformDate from '../utils/DatePickerPersistence'; const RealDatePickerRange = lazy(datePickerRange); +const end_date = transformDate; +const start_date = transformDate; /** * DatePickerRange is a tailor made component designed for selecting @@ -266,28 +267,8 @@ DatePickerRange.propTypes = { }; DatePickerRange.persistenceTransforms = { - end_date: { - extract: propValue => { - if (!isNil(propValue)) { - return moment(propValue) - .startOf('day') - .format('YYYY-MM-DD'); - } - return propValue; - }, - apply: storedValue => storedValue, - }, - start_date: { - extract: propValue => { - if (!isNil(propValue)) { - return moment(propValue) - .startOf('day') - .format('YYYY-MM-DD'); - } - return propValue; - }, - apply: storedValue => storedValue, - }, + end_date, + start_date, }; DatePickerRange.defaultProps = { diff --git a/src/components/DatePickerSingle.react.js b/src/components/DatePickerSingle.react.js index 431e14651..37c591baa 100644 --- a/src/components/DatePickerSingle.react.js +++ b/src/components/DatePickerSingle.react.js @@ -1,8 +1,7 @@ import PropTypes from 'prop-types'; import React, {Component, lazy, Suspense} from 'react'; import datePickerSingle from '../utils/LazyLoader/datePickerSingle'; -import moment from 'moment'; -import {isNil} from 'ramda'; +import date from '../utils/DatePickerPersistence'; const RealDateSingleRange = lazy(datePickerSingle); @@ -223,17 +222,7 @@ DatePickerSingle.propTypes = { }; DatePickerSingle.persistenceTransforms = { - date: { - extract: propValue => { - if (!isNil(propValue)) { - return moment(propValue) - .startOf('day') - .format('YYYY-MM-DD'); - } - return propValue; - }, - apply: storedValue => storedValue, - }, + date, }; DatePickerSingle.defaultProps = { diff --git a/src/utils/DatePickerPersistence.js b/src/utils/DatePickerPersistence.js new file mode 100644 index 000000000..4a18a04f5 --- /dev/null +++ b/src/utils/DatePickerPersistence.js @@ -0,0 +1,14 @@ +import moment from 'moment'; +import {isNil} from 'ramda'; + +export default { + extract: propValue => { + if (!isNil(propValue)) { + return moment(propValue) + .startOf('day') + .format('YYYY-MM-DD'); + } + return propValue; + }, + apply: storedValue => storedValue, +}; From d80a500fa1d76a46384a211fcdcb447b8f8a955c Mon Sep 17 00:00:00 2001 From: harrisonn Date: Fri, 4 Sep 2020 14:53:47 -0400 Subject: [PATCH 17/20] noise From 6df0230cc12f6fc21d7ce122aa361e1b01ce9911 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Fri, 4 Sep 2020 16:41:44 -0400 Subject: [PATCH 18/20] remove dash branch to test against new dash dev in ci --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b94c555b7..31961700a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -80,7 +80,7 @@ jobs: command: | . venv/bin/activate && mkdir packages # build main dash - git clone -b persistence-hg --depth 1 https://github.com/plotly/dash.git dash-main + git clone --depth 1 https://github.com/plotly/dash.git dash-main cd dash-main && pip install -e .[dev] --progress-bar off && python setup.py sdist && mv dist/* ../packages/ cd dash-renderer && npm ci && npm run build python setup.py sdist && mv dist/* ../../packages/ && cd ../.. From c0f98b4d7da5c1e1666332183cfc9e5e4a0241a2 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Fri, 4 Sep 2020 16:46:36 -0400 Subject: [PATCH 19/20] change transformDate prop assignment --- src/components/DatePickerRange.react.js | 6 ++---- src/components/DatePickerSingle.react.js | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/DatePickerRange.react.js b/src/components/DatePickerRange.react.js index be243120e..b0352850d 100644 --- a/src/components/DatePickerRange.react.js +++ b/src/components/DatePickerRange.react.js @@ -4,8 +4,6 @@ import datePickerRange from '../utils/LazyLoader/datePickerRange'; import transformDate from '../utils/DatePickerPersistence'; const RealDatePickerRange = lazy(datePickerRange); -const end_date = transformDate; -const start_date = transformDate; /** * DatePickerRange is a tailor made component designed for selecting @@ -267,8 +265,8 @@ DatePickerRange.propTypes = { }; DatePickerRange.persistenceTransforms = { - end_date, - start_date, + end_date: transformDate, + start_date: transformDate, }; DatePickerRange.defaultProps = { diff --git a/src/components/DatePickerSingle.react.js b/src/components/DatePickerSingle.react.js index 37c591baa..11c3cbfcb 100644 --- a/src/components/DatePickerSingle.react.js +++ b/src/components/DatePickerSingle.react.js @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React, {Component, lazy, Suspense} from 'react'; import datePickerSingle from '../utils/LazyLoader/datePickerSingle'; -import date from '../utils/DatePickerPersistence'; +import transformDate from '../utils/DatePickerPersistence'; const RealDateSingleRange = lazy(datePickerSingle); @@ -222,7 +222,7 @@ DatePickerSingle.propTypes = { }; DatePickerSingle.persistenceTransforms = { - date, + date: transformDate, }; DatePickerSingle.defaultProps = { From 0519d8907d605f7ca723ce89775e0fc654a01507 Mon Sep 17 00:00:00 2001 From: harrisonn Date: Fri, 4 Sep 2020 16:57:47 -0400 Subject: [PATCH 20/20] update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53f1b2fa2..56fcf614c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Fixed +- [#854](https://github.com/plotly/dash-core-components/pull/854) Used `persistenceTransforms` to strip the time part of the datetime in the persited props of DatePickerSingle (date) and DatePickerRange (end_date, start_date), fixing [dcc#700](https://github.com/plotly/dash-core-components/issues/700). + ### Added - [#850](https://github.com/plotly/dash-core-components/pull/850) Add property `prependData` to `Graph` to support `Plotly.prependTraces` + refactored the existing `extendTraces` API to be a single `mergeTraces` API that can handle both `prepend` as well as `extend`.