diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ddef7d826..221f8979df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - [#3284](https://github.com/plotly/dash/pull/3284) Fix component as props having the same key when used in the same container. - [#3287](https://github.com/plotly/dash/pull/3287) Fix typing component generation & explicitize_args. - [#3282](https://github.com/plotly/dash/pull/3282) Fix incorrect cancellation of pattern matched long callbacks. +- [#3289](https://github.com/plotly/dash/pull/3289) Fixed issue with debugTitle where status doesnt exist and allow_duplicates to ignore the hash for prop loading in the target. ## [3.0.3] - 2025-04-14 diff --git a/components/dash-core-components/src/fragments/Loading/spinners/CircleSpinner.jsx b/components/dash-core-components/src/fragments/Loading/spinners/CircleSpinner.jsx index 19c61411e5..1a486d77f1 100644 --- a/components/dash-core-components/src/fragments/Loading/spinners/CircleSpinner.jsx +++ b/components/dash-core-components/src/fragments/Loading/spinners/CircleSpinner.jsx @@ -16,7 +16,7 @@ const CircleSpinner = ({ style, }) => { let debugTitle; - if (debug) { + if (debug && status) { debugTitle = status.map((s) => ); } let spinnerClass = fullscreen ? 'dash-spinner-container' : ''; diff --git a/components/dash-core-components/src/fragments/Loading/spinners/CubeSpinner.jsx b/components/dash-core-components/src/fragments/Loading/spinners/CubeSpinner.jsx index bb44c0bbd7..936ec5fd8c 100644 --- a/components/dash-core-components/src/fragments/Loading/spinners/CubeSpinner.jsx +++ b/components/dash-core-components/src/fragments/Loading/spinners/CubeSpinner.jsx @@ -7,7 +7,7 @@ import DebugTitle from './DebugTitle.jsx'; const CubeSpinner = ({status, color, fullscreen, debug, className, style}) => { let debugTitle; - if (debug) { + if (debug && status) { debugTitle = status.map((s) => ); } let spinnerClass = fullscreen ? 'dash-spinner-container' : ''; diff --git a/components/dash-core-components/src/fragments/Loading/spinners/DefaultSpinner.jsx b/components/dash-core-components/src/fragments/Loading/spinners/DefaultSpinner.jsx index 2ec51bc9a5..0d9c7d4924 100644 --- a/components/dash-core-components/src/fragments/Loading/spinners/DefaultSpinner.jsx +++ b/components/dash-core-components/src/fragments/Loading/spinners/DefaultSpinner.jsx @@ -15,7 +15,7 @@ const DefaultSpinner = ({ style, }) => { let debugTitle; - if (debug) { + if (debug && status) { debugTitle = status.map((s) => ); } let spinnerClass = fullscreen ? 'dash-spinner-container' : ''; diff --git a/components/dash-core-components/src/fragments/Loading/spinners/DotSpinner.jsx b/components/dash-core-components/src/fragments/Loading/spinners/DotSpinner.jsx index 1ea1dc1c25..c6a0906449 100644 --- a/components/dash-core-components/src/fragments/Loading/spinners/DotSpinner.jsx +++ b/components/dash-core-components/src/fragments/Loading/spinners/DotSpinner.jsx @@ -8,7 +8,7 @@ import DebugTitle from './DebugTitle.jsx'; */ const DotSpinner = ({status, color, fullscreen, debug, className, style}) => { let debugTitle; - if (debug) { + if (debug && status) { debugTitle = status.map((s) => ); } let spinnerClass = fullscreen ? 'dash-spinner-container' : ''; diff --git a/components/dash-core-components/src/fragments/Loading/spinners/GraphSpinner.jsx b/components/dash-core-components/src/fragments/Loading/spinners/GraphSpinner.jsx index f4a4e06b32..f79ff2ac83 100644 --- a/components/dash-core-components/src/fragments/Loading/spinners/GraphSpinner.jsx +++ b/components/dash-core-components/src/fragments/Loading/spinners/GraphSpinner.jsx @@ -5,7 +5,7 @@ import DebugTitle from './DebugTitle.jsx'; const GraphSpinner = ({status, fullscreen, debug, className, style}) => { let debugTitle; - if (debug) { + if (debug && status) { debugTitle = status.map((s) => ); } let spinnerClass = fullscreen ? 'dash-spinner-container' : ''; diff --git a/components/dash-core-components/tests/integration/loading/test_loading_component.py b/components/dash-core-components/tests/integration/loading/test_loading_component.py index a7500daeba..597bc396ff 100644 --- a/components/dash-core-components/tests/integration/loading/test_loading_component.py +++ b/components/dash-core-components/tests/integration/loading/test_loading_component.py @@ -689,3 +689,69 @@ def updateDiv(n_clicks): dash_dcc.wait_for_text_to_equal("#div-1", "changed") assert dash_dcc.get_logs() == [] + + +# multiple components, only one triggers the spinner +def test_ldcp017_loading_component_target_components_duplicates(dash_dcc): + + lock = Lock() + + app = Dash(__name__) + + app.layout = html.Div( + [ + dcc.Loading( + [ + html.Button(id="btn-1"), + html.Button(id="btn-2", children="content 2"), + ], + className="loading-1", + target_components={"btn-2": "children"}, + debug=True, + ) + ], + id="root", + ) + + @app.callback(Output("btn-1", "children"), [Input("btn-2", "n_clicks")]) + def updateDiv1(n_clicks): + if n_clicks: + with lock: + return "changed 1" + + return "content 1" + + @app.callback( + Output("btn-2", "children", allow_duplicate=True), + [Input("btn-1", "n_clicks")], + prevent_initial_call=True, + ) + def updateDiv2(n_clicks): + if n_clicks: + with lock: + return "changed 2" + + return "content 2" + + dash_dcc.start_server(app) + + dash_dcc.wait_for_text_to_equal("#btn-1", "content 1") + dash_dcc.wait_for_text_to_equal("#btn-2", "content 2") + + with lock: + dash_dcc.find_element("#btn-1").click() + + dash_dcc.find_element(".loading-1 .dash-spinner") + dash_dcc.wait_for_text_to_equal("#btn-2", "") + + dash_dcc.wait_for_text_to_equal("#btn-2", "changed 2") + + with lock: + dash_dcc.find_element("#btn-2").click() + spinners = dash_dcc.find_elements(".loading-1 .dash-spinner") + dash_dcc.wait_for_text_to_equal("#btn-1", "") + + dash_dcc.wait_for_text_to_equal("#btn-1", "changed 1") + assert spinners == [] + + assert dash_dcc.get_logs() == [] diff --git a/dash/dash-renderer/src/actions/callbacks.ts b/dash/dash-renderer/src/actions/callbacks.ts index 4cbd6a3d04..82c7211446 100644 --- a/dash/dash-renderer/src/actions/callbacks.ts +++ b/dash/dash-renderer/src/actions/callbacks.ts @@ -748,7 +748,7 @@ export function executeCallback( const __execute = async (): Promise => { const loadingOutputs = outputs.map(out => ({ path: getPath(paths, out.id), - property: out.property, + property: out.property?.split('@')[0], id: out.id })); dispatch(loading(loadingOutputs));