Skip to content

Commit cb84367

Browse files
authored
Merge branch 'dev' into feat/global-set-props
2 parents d6564d8 + 9a4a479 commit cb84367

File tree

31 files changed

+568
-225
lines changed

31 files changed

+568
-225
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
4+
const AddPropsComponent = (props) => {
5+
const {children, id} = props;
6+
7+
8+
return (
9+
<div id={id}>
10+
{React.cloneElement(children, {
11+
receive: `Element #${id} pass`,
12+
id: id,
13+
})}
14+
</div>
15+
);
16+
};
17+
18+
AddPropsComponent.propTypes = {
19+
id: PropTypes.string,
20+
children: PropTypes.node,
21+
};
22+
23+
export default AddPropsComponent;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React, { useState, useEffect } from "react";
2+
import PropTypes from "prop-types";
3+
4+
const DrawCounter = (props) => {
5+
const [count, setCount] = useState(0);
6+
useEffect(() => {
7+
setCount(count + 1);
8+
}, [props]);
9+
return <div id={props.id}>{count}</div>;
10+
};
11+
12+
DrawCounter.propTypes = {
13+
id: PropTypes.string,
14+
};
15+
export default DrawCounter;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
const ReceivePropsComponent = (props) => {
5+
const {id, text, receive} = props;
6+
7+
return (
8+
<div id={id}>
9+
{receive || text}
10+
</div>
11+
);
12+
}
13+
ReceivePropsComponent.propTypes = {
14+
id: PropTypes.string,
15+
text: PropTypes.string,
16+
receive: PropTypes.string,
17+
}
18+
19+
export default ReceivePropsComponent;

@plotly/dash-test-components/src/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ import StyledComponent from './components/StyledComponent';
88
import WidthComponent from './components/WidthComponent';
99
import ComponentAsProp from './components/ComponentAsProp';
1010

11+
import DrawCounter from './components/DrawCounter';
12+
import AddPropsComponent from "./components/AddPropsComponent";
13+
import ReceivePropsComponent from "./components/ReceivePropsComponent";
14+
15+
1116
export {
1217
AsyncComponent,
1318
CollapseComponent,
@@ -18,4 +23,7 @@ export {
1823
StyledComponent,
1924
WidthComponent,
2025
ComponentAsProp,
26+
DrawCounter,
27+
AddPropsComponent,
28+
ReceivePropsComponent
2129
};

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,22 @@ This project adheres to [Semantic Versioning](https://semver.org/).
66

77
## Added
88

9+
- [#2832](https://github.com/plotly/dash/pull/2832) Add dash startup route setup on Dash init.
10+
- [#2819](https://github.com/plotly/dash/pull/2819) Add dash subcomponents receive additional parameters passed by the parent component. Fixes [#2814](https://github.com/plotly/dash/issues/2814).
11+
- [#2826](https://github.com/plotly/dash/pull/2826) When using Pages, allows for `app.title` and (new) `app.description` to be used as defaults for the page title and description. Fixes [#2811](https://github.com/plotly/dash/issues/2811).
912
- [#2795](https://github.com/plotly/dash/pull/2795) Allow list of components to be passed as layout.
10-
- [2760](https://github.com/plotly/dash/pull/2760) New additions to dcc.Loading resolving multiple issues:
13+
- [#2760](https://github.com/plotly/dash/pull/2760) New additions to dcc.Loading resolving multiple issues:
1114
- `delay_show` and `delay_hide` props to prevent flickering during brief loading periods (similar to Dash Bootstrap Components dbc.Spinner)
1215
- `overlay_style` for styling the loading overlay, such as setting visibility and opacity for children
1316
- `target_components` specifies components/props triggering the loading spinner
1417
- `custom_spinner` enables using a custom component for loading messages instead of built-in spinners
1518
- `display` overrides the loading status with options for "show," "hide," or "auto"
1619

20+
## Fixed
21+
22+
- [#2362](https://github.com/plotly/dash/pull/2362) Global namespace not polluted any more when loading clientside callbacks.
23+
- [#2833](https://github.com/plotly/dash/pull/2833) Allow data url in link props. Fixes [#2764](https://github.com/plotly/dash/issues/2764)
24+
1725
## [2.16.1] - 2024-03-06
1826

1927
## Fixed

components/dash-core-components/package-lock.json

Lines changed: 0 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/dash-core-components/package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
"maintainer": "Alex Johnson <[email protected]>",
3636
"license": "MIT",
3737
"dependencies": {
38-
"@braintree/sanitize-url": "^7.0.0",
3938
"@fortawesome/fontawesome-svg-core": "1.2.36",
4039
"@fortawesome/free-regular-svg-icons": "^5.15.4",
4140
"@fortawesome/free-solid-svg-icons": "^5.15.4",
@@ -87,13 +86,15 @@
8786
"react": "^16.14.0",
8887
"react-dom": "^16.14.0",
8988
"react-jsx-parser": "1.21.0",
89+
"rimraf": "^5.0.5",
9090
"style-loader": "^3.3.3",
9191
"styled-jsx": "^3.4.4",
9292
"webpack": "^5.90.3",
93-
"webpack-cli": "^5.1.4",
94-
"rimraf": "^5.0.5"
93+
"webpack-cli": "^5.1.4"
94+
},
95+
"optionalDependencies": {
96+
"fsevents": "*"
9597
},
96-
"optionalDependencies": { "fsevents": "*" },
9798
"files": [
9899
"/dash_core_components/*{.js,.map}",
99100
"/lib/"

components/dash-core-components/src/components/Link.react.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import PropTypes from 'prop-types';
22

33
import React, {useEffect, useMemo} from 'react';
4-
import {sanitizeUrl} from '@braintree/sanitize-url';
54
import {isNil} from 'ramda';
65

76
/*
@@ -46,8 +45,9 @@ const Link = props => {
4645
refresh,
4746
setProps,
4847
} = props;
48+
const cleanUrl = window.dash_clientside.clean_url;
4949
const sanitizedUrl = useMemo(() => {
50-
return href ? sanitizeUrl(href) : undefined;
50+
return href ? cleanUrl(href) : undefined;
5151
}, [href]);
5252

5353
const updateLocation = e => {

components/dash-core-components/src/fragments/Dropdown.react.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ const Dropdown = props => {
3939
const {
4040
id,
4141
clearable,
42-
searchable,
4342
multi,
4443
options,
4544
setProps,
45+
search_value,
4646
style,
4747
loading_state,
4848
value,
@@ -122,7 +122,7 @@ const Dropdown = props => {
122122

123123
useEffect(() => {
124124
if (
125-
!searchable &&
125+
!search_value &&
126126
!isNil(sanitizedOptions) &&
127127
optionsCheck !== sanitizedOptions &&
128128
!isNil(value)

components/dash-core-components/tests/integration/dropdown/test_remove_option.py

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import json
22

3-
from dash import Dash, html, dcc, Output, Input
3+
import pytest
4+
5+
from dash import Dash, html, dcc, Output, Input, State
46
from dash.exceptions import PreventUpdate
57

68

@@ -11,7 +13,8 @@
1113
]
1214

1315

14-
def test_ddro001_remove_option_single(dash_dcc):
16+
@pytest.mark.parametrize("searchable", (True, False))
17+
def test_ddro001_remove_option_single(dash_dcc, searchable):
1518
dropdown_options = sample_dropdown_options
1619

1720
app = Dash(__name__)
@@ -22,7 +25,7 @@ def test_ddro001_remove_option_single(dash_dcc):
2225
dcc.Dropdown(
2326
options=dropdown_options,
2427
value=value,
25-
searchable=False,
28+
searchable=searchable,
2629
id="dropdown",
2730
),
2831
html.Button("Remove option", id="remove"),
@@ -38,18 +41,17 @@ def on_click(n_clicks):
3841

3942
@app.callback(Output("value-output", "children"), [Input("dropdown", "value")])
4043
def on_change(val):
41-
if not val:
42-
raise PreventUpdate
43-
return val or "None"
44+
return val or "Nothing Here"
4445

4546
dash_dcc.start_server(app)
4647
btn = dash_dcc.wait_for_element("#remove")
4748
btn.click()
4849

49-
dash_dcc.wait_for_text_to_equal("#value-output", "None")
50+
dash_dcc.wait_for_text_to_equal("#value-output", "Nothing Here")
5051

5152

52-
def test_ddro002_remove_option_multi(dash_dcc):
53+
@pytest.mark.parametrize("searchable", (True, False))
54+
def test_ddro002_remove_option_multi(dash_dcc, searchable):
5355
dropdown_options = sample_dropdown_options
5456

5557
app = Dash(__name__)
@@ -62,7 +64,7 @@ def test_ddro002_remove_option_multi(dash_dcc):
6264
value=value,
6365
multi=True,
6466
id="dropdown",
65-
searchable=False,
67+
searchable=searchable,
6668
),
6769
html.Button("Remove option", id="remove"),
6870
html.Div(id="value-output"),
@@ -84,3 +86,64 @@ def on_change(val):
8486
btn.click()
8587

8688
dash_dcc.wait_for_text_to_equal("#value-output", '["MTL"]')
89+
90+
91+
def test_ddro003_remove_option_multiple_dropdowns(dash_dcc):
92+
app = Dash(__name__)
93+
app.layout = html.Div(
94+
[
95+
dcc.Dropdown(
96+
id="available-options",
97+
multi=True,
98+
options=sample_dropdown_options,
99+
value=["MTL", "NYC", "SF"],
100+
),
101+
dcc.Dropdown(
102+
id="chosen",
103+
multi=True,
104+
options=sample_dropdown_options,
105+
value=["NYC", "SF"],
106+
),
107+
html.Button(id="remove-btn", children="Remove"),
108+
html.Button(id="submit-btn", children="Submit"),
109+
html.Div(id="value-output"),
110+
html.Div(id="options-output"),
111+
],
112+
)
113+
114+
@app.callback(
115+
Output("chosen", "options"),
116+
Input("available-options", "value"),
117+
)
118+
def update_options(available_options):
119+
if available_options is None:
120+
return []
121+
else:
122+
return [{"label": i, "value": i} for i in available_options]
123+
124+
@app.callback(
125+
Output("available-options", "options"), [Input("remove-btn", "n_clicks")]
126+
)
127+
def on_click(n_clicks):
128+
if not n_clicks:
129+
raise PreventUpdate
130+
return sample_dropdown_options[:-1]
131+
132+
@app.callback(
133+
[Output("value-output", "children"), Output("options-output", "children")],
134+
Input("submit-btn", "n_clicks"),
135+
State("chosen", "options"),
136+
State("chosen", "value"),
137+
)
138+
def print_value(n_clicks, options, value):
139+
if not n_clicks:
140+
raise PreventUpdate
141+
return [json.dumps(value), json.dumps([i["value"] for i in options])]
142+
143+
dash_dcc.start_server(app)
144+
btn = dash_dcc.wait_for_element("#remove-btn")
145+
btn.click()
146+
btn = dash_dcc.wait_for_element("#submit-btn")
147+
btn.click()
148+
dash_dcc.wait_for_text_to_equal("#value-output", '["NYC"]')
149+
dash_dcc.wait_for_text_to_equal("#options-output", '["MTL", "NYC"]')

0 commit comments

Comments
 (0)