diff --git a/.circleci/config.yml b/.circleci/config.yml index 89932cb..f22d1d7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,14 +39,16 @@ jobs: name: Install dependencies (dash) command: | git clone git@github.com:plotly/dash.git - git clone --branch fix-prop-types git@github.com:plotly/dash-core-components.git + git clone git@github.com:plotly/dash-core-components.git git clone git@github.com:plotly/dash-html-components.git git clone git@github.com:plotly/dash-table.git + git clone git@github.com:plotly/dash-renderer-test-components . venv/bin/activate pip install -e ./dash --quiet cd dash-core-components && npm install --ignore-scripts && npm run build && pip install -e . && cd .. cd dash-html-components && npm install --ignore-scripts && npm run build && pip install -e . && cd .. cd dash-table && npm install --ignore-scripts && npm run build && pip install -e . && cd .. + cd dash-renderer-test-components && npm install --ignore-scripts && npm run build:all && pip install -e . && cd .. - run: name: Build diff --git a/src/APIController.react.js b/src/APIController.react.js index 165044a..ceb4d87 100644 --- a/src/APIController.react.js +++ b/src/APIController.react.js @@ -119,11 +119,19 @@ class UnconnectedContainer extends Component { ) { return ( - + ); } else if (appLifecycle === getAppState('HYDRATED')) { - return ; + return ( + + ); } return
{'Loading...'}
; diff --git a/src/TreeContainer.js b/src/TreeContainer.js index 900a761..7f6e44a 100644 --- a/src/TreeContainer.js +++ b/src/TreeContainer.js @@ -4,7 +4,9 @@ import Registry from './registry'; import {propTypeErrorHandler} from './exceptions'; import {connect} from 'react-redux'; import { + addIndex, any, + concat, contains, filter, forEach, @@ -50,11 +52,12 @@ function validateComponent(componentDefinition) { } } -const createContainer = component => isSimpleComponent(component) ? +const createContainer = (component, path) => isSimpleComponent(component) ? component : (); function CheckedComponent(p) { @@ -87,14 +90,16 @@ CheckedComponent.propTypes = { id: PropTypes.string, }; class TreeContainer extends Component { - getChildren(components) { + getChildren(components, path) { if (isNil(components)) { return null; } return Array.isArray(components) ? - map(createContainer, components) : - createContainer(components); + addIndex(map)( + (component, i) => createContainer(component, concat(path, ['props', 'children', i])), + components + ) : createContainer(components, concat(path, ['props', 'children'])); } getComponent(_dashprivate_layout, children, loading_state, setProps) { @@ -148,7 +153,7 @@ class TreeContainer extends Component { const { _dashprivate_dependencies, _dashprivate_dispatch, - _dashprivate_paths + _dashprivate_path } = this.props; const id = this.getLayoutProps().id; @@ -165,8 +170,7 @@ class TreeContainer extends Component { // Always update this component's props _dashprivate_dispatch(updateProps({ props: newProps, - id: id, - itempath: _dashprivate_paths[id] + itempath: _dashprivate_path })); // Only dispatch changes to Dash if a watched prop changed @@ -194,12 +198,13 @@ class TreeContainer extends Component { const { _dashprivate_dispatch, _dashprivate_layout, - _dashprivate_loadingState + _dashprivate_loadingState, + _dashprivate_path } = this.props; const layoutProps = this.getLayoutProps(); - const children = this.getChildren(layoutProps.children); + const children = this.getChildren(layoutProps.children, _dashprivate_path); const setProps = this.getSetProps(_dashprivate_dispatch); return this.getComponent(_dashprivate_layout, children, _dashprivate_loadingState, setProps); @@ -211,9 +216,9 @@ TreeContainer.propTypes = { _dashprivate_dispatch: PropTypes.func, _dashprivate_layout: PropTypes.object, _dashprivate_loadingState: PropTypes.object, - _dashprivate_paths: PropTypes.any, _dashprivate_requestQueue: PropTypes.any, _dashprivate_config: PropTypes.object, + _dashprivate_path: PropTypes.array, }; function isLoadingComponent(layout) { @@ -286,7 +291,6 @@ function getLoadingState(layout, requestQueue) { export const AugmentedTreeContainer = connect( state => ({ dependencies: state.dependenciesRequest.content, - paths: state.paths, requestQueue: state.requestQueue, config: state.config }), @@ -295,8 +299,8 @@ export const AugmentedTreeContainer = connect( _dashprivate_dependencies: stateProps.dependencies, _dashprivate_dispatch: dispatchProps.dispatch, _dashprivate_layout: ownProps._dashprivate_layout, + _dashprivate_path: ownProps._dashprivate_path, _dashprivate_loadingState: getLoadingState(ownProps._dashprivate_layout, stateProps.requestQueue), - _dashprivate_paths: stateProps.paths, _dashprivate_requestQueue: stateProps.requestQueue, _dashprivate_config: stateProps.config, }) diff --git a/tests/test_render.py b/tests/test_render.py index 308308b..8b51f5f 100644 --- a/tests/test_render.py +++ b/tests/test_render.py @@ -8,6 +8,7 @@ from dash.development.base_component import Component import dash_html_components as html import dash_core_components as dcc +import dash_renderer_test_components from bs4 import BeautifulSoup from selenium.webdriver.common.action_chains import ActionChains @@ -2960,3 +2961,32 @@ def display_content(pathname): test_cases[test_case_id]['name'] ) ) + + def test_set_props_behavior(self): + app = dash.Dash(__name__) + app.layout = html.Div([ + dash_renderer_test_components.UncontrolledInput( + id='id', + value='' + ), + html.Div( + id='container', + children=dash_renderer_test_components.UncontrolledInput( + value='' + ), + ) + ]) + + self.startServer( + app, + debug=True, + use_reloader=False, + use_debugger=True, + dev_tools_hot_reload=False, + ) + + self.wait_for_element_by_css_selector('#id').send_keys('hello input with ID') + self.wait_for_text_to_equal('#id', 'hello input with ID') + + self.wait_for_element_by_css_selector('#container input').send_keys('hello input without ID') + self.wait_for_text_to_equal('#container input', 'hello input without ID')