Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
- [#3465](https://github.com/plotly/dash/pull/3465) Plotly cloud integrations, add devtool API, placeholder plotly cloud CLI & publish button, `dash[cloud]` extra dependencies.

## Fixed
- [#3490](https://github.com/plotly/dash/pull/3490) Fix stack overflow when circular callbacks are displayed on the devtool callback
- [#3395](https://github.com/plotly/dash/pull/3395) Fix Components added through set_props() cannot trigger related callback functions. Fix [#3316](https://github.com/plotly/dash/issues/3316)
- [#3415](https://github.com/plotly/dash/pull/3415) Fix the error triggered when only a single no_update is returned for client-side callback functions with multiple Outputs. Fix [#3366](https://github.com/plotly/dash/issues/3366)
- [#3416](https://github.com/plotly/dash/issues/3416) Fix DeprecationWarning in dash/_jupyter.py by migrating from deprecated ipykernel.comm.Comm to comm module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ function getEdgeTypes(node) {
* @returns {function} - cleanup function, for useEffect hook
*/
export function updateSelectedNode(cy, id) {
function ascend(node, collection) {
// FIXME: Should we include State parents but non-recursively?
function ascend(node, collection, visited = new Set()) {
if (visited.has(node.id())) {
return;
}
visited.add(node.id());
const type = node.data().type === 'callback' ? 'input' : 'output';
const edges = getEdgeTypes(node)[type];
const parents = edges.sources();
Expand All @@ -37,10 +40,14 @@ export function updateSelectedNode(cy, id) {
if (node.data().type === 'property') {
collection.merge(node.ancestors());
}
parents.forEach(node => ascend(node, collection));
parents.forEach(node => ascend(node, collection, visited));
}

function descend(node, collection) {
function descend(node, collection, visited = new Set()) {
if (visited.has(node.id())) {
return;
}
visited.add(node.id());
const type = node.data().type === 'callback' ? 'output' : 'input';
const edges = getEdgeTypes(node)[type];
const children = edges.targets();
Expand All @@ -49,7 +56,7 @@ export function updateSelectedNode(cy, id) {
if (node.data().type === 'property') {
collection.merge(node.ancestors());
}
children.forEach(node => descend(node, collection));
children.forEach(node => descend(node, collection, visited));
}

if (id) {
Expand All @@ -63,8 +70,6 @@ export function updateSelectedNode(cy, id) {
// all all ancestors and descendants that are connected via Inputs
// or Outputs (but not State).

// WARNING: No cycle detection!

const subtree = cy.collection();
subtree.merge(node);
ascend(node, subtree);
Expand Down