Skip to content

DYN-10081: Preserve warnings/info stack format and Batch node info updates#16955

Open
zeusongit wants to merge 5 commits intoDynamoDS:masterfrom
zeusongit:10081
Open

DYN-10081: Preserve warnings/info stack format and Batch node info updates#16955
zeusongit wants to merge 5 commits intoDynamoDS:masterfrom
zeusongit:10081

Conversation

@zeusongit
Copy link
Contributor

Purpose

TL;DR
Fixes a bug where Info and Warning bubbles couldn't coexist on non-chart nodes (info would silently wipe the warning from the Infos collection), plus performance and lifecycle improvements to the bubble system.

Problem

  • Info supersedes Warning on non-chart nodes — When Info() is called after Warning(), the state restoration in Info() triggers ClearTransientWarningsAndErrors() as a side effect of the State setter, wiping the Warning entry from Infos. Chart nodes don't hit this because they use persistent variants.
  • O(n²) event cascade in bubble updates — Each NodeMessages.Add() triggers a full RefreshNodeInformationalStateDisplay() rebuild (clears and repopulates 3 display collections with ~30 events each). For N messages, this means N full rebuilds per update.
  • ClearInfoMessages() could accidentally demote Warning/Error states — Setting State = Active unconditionally triggered the setter side effect, clearing transient warnings.
  • Info.GetHashCode() operator precedence bug — Missing parentheses caused the hash seed to be discarded and null Message to throw NRE.

Changes

  • Added suppressTransientClear flag to prevent Info() state restoration from triggering ClearTransientWarningsAndErrors(). Now Warning+Info entries coexist in Infos and both render in the bubble, stacked like chart nodes.
  • ClearInfoMessages() no longer unconditionally sets State = Active. Added fallthrough else branch for when State doesn't match Info/PersistentInfo.
  • Fixed GetHashCode() precedence: hash * 23 + (Message == null ? 0 : Message.GetHashCode()).
  • Moved all 5 event subscriptions inside if (ErrorBubble == null) guard in BuildErrorBubble() to prevent potential double-subscription. Added Contains check before Errors.Add.
  • Added batchUpdateDepth counter with BeginBatchUpdate()/EndBatchUpdate() (nesting-safe).

What this enables

All three bubble sections (Error, Warning, Info) can now coexist on any node — not just chart nodes. The node's bottom bar reflects the highest-priority state, and the bubble stacks sections vertically: Errors (red) → Warnings (orange) → Info (blue).

Before:
Screenshot 2026-03-11 133259

After:
Screenshot 2026-03-11 152617

Declarations

Check these if you believe they are true

Release Notes

Fixed a bug where Info and Warning bubbles couldn't coexist on non-chart nodes (info would silently wipe the warning from the Infos collection), plus performance and lifecycle improvements to the bubble system.

Reviewers

(FILL ME IN) Reviewer 1 (If possible, assign the Reviewer for the PR)

(FILL ME IN, optional) Any additional notes to reviewers or testers.

FYIs

(FILL ME IN, Optional) Names of anyone else you wish to be notified of

Prevent transient warnings/errors from being cleared when restoring node State during Info() by adding a suppressTransientClear flag and scoping State assignments. Adjust ClearInfoMessages so only info-related states are promoted back to Active and other states (Warning/Error) keep their state while still removing info entries. Add batching to InfoBubble/NodeViewModel updates (BeginBatchUpdate/EndBatchUpdate and dispatcher invocation) to avoid repeated RefreshNodeInformationalStateDisplay calls and duplicate subscriptions/Workspace error entries. Minor fixes: tighten GetHashCode parentheses and add Clear() to ObservableHashSet. Overall: correctness (preserve warnings) and performance (batch updates, avoid double-subscribe).
@zeusongit zeusongit requested review from a team and Copilot March 11, 2026 19:44
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the ticket for this pull request: https://jira.autodesk.com/browse/DYN-10081

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes and improves the node “bubble” messaging system so Info and Warning/Error bubbles can coexist (stacked) on non-chart nodes, while also reducing redundant UI refresh work during message updates.

Changes:

  • Prevents NodeModel.Info() state restoration from clearing transient warnings/errors, allowing Warning+Info to coexist in Infos.
  • Adds batching to suppress per-item RefreshNodeInformationalStateDisplay() rebuilds during NodeMessages updates.
  • Improves bubble lifecycle/subscription handling and fixes Info.GetHashCode() operator precedence.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/DynamoUtilities/ObservableHashSet.cs Adds Clear() with collection reset notification support.
src/DynamoCoreWpf/ViewModels/Preview/InfoBubbleViewModel.cs Adds nested batch update tracking to suppress repeated refresh during bulk NodeMessages updates; disposes more cleanly.
src/DynamoCoreWpf/ViewModels/Core/NodeViewModel.cs Batches bubble message updates, prevents duplicate subscriptions, avoids duplicate Errors insertion, and nulls ErrorBubble on dispose.
src/DynamoCore/Graph/Nodes/NodeModel.cs Fixes GetHashCode(), adds suppression flag for state restoration side-effects, and updates ClearInfoMessages() / Info() behavior.

You can also share your feedback on Copilot code review. Take the survey.

/// Info() state restoration. Access is single-threaded (NodeModel state mutations
/// are not thread-safe by design).
/// </summary>
private bool suppressTransientClear;
Copy link
Contributor

@aparajit-pratap aparajit-pratap Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be named suppressClearTransient or suppressClearTransientMessages - something like that, since you're suppressing the clearing.

// For any other state (Warning, Error, Active, Dead, etc.), clear all info types.
// This fixes the case where State was restored (e.g., by Info() method) and no
// longer matches Info/PersistentInfo, but info entries still exist in Infos.
infos.RemoveWhere(x => x.State == ElementState.PersistentInfo || x.State == ElementState.Info);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This confusing naming has been there for a while. We have a notion of Info vs Warning messages, but we still maintain a type with the same conflicting name, "Info", that actually can be any type of message, even warning or error.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a good time to rename some of these fields/properties to something more sensible and have a clear separation of meaning?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will look into this, this has bothered me for a while too

CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, range));
}

public void Clear()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this new method called?

Copy link
Contributor

@aparajit-pratap aparajit-pratap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments and questions, then LGTM!

Rename the private boolean suppressTransientClear to suppressClearTransientMessages in NodeModel and update all references accordingly. The flag is used to suppress clearing transient warnings/errors during state/Info restoration. Also remove the public Clear() method from ObservableHashSet<T> (and its Reset event invocation), so the collection no longer exposes a Clear API.
@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants