Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DYN-8334 Node Cluster Visual Preparation Work #15865

Merged
merged 36 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7a7bbf3
Single Node Placement and Performance report
QilongTang Jul 11, 2024
9afee56
Creating three nodes in a row
QilongTang Jul 12, 2024
5f57c94
Add feature flag check
QilongTang Jul 15, 2024
89a2932
Merge branch 'master' into NodeClusterPlacementPerformance
QilongTang Jul 16, 2024
4c73df7
Merge branch 'master' into NodeClusterPlacementPerformance
QilongTang Jul 16, 2024
21a5e21
Update
QilongTang Jul 16, 2024
b05693b
update
QilongTang Jul 19, 2024
7dd493a
Add IsPreview State to Node
QilongTang Jul 19, 2024
bee6fb9
update
QilongTang Jul 19, 2024
b21bb6f
add comment
QilongTang Jul 19, 2024
2ca671f
Update
QilongTang Jul 22, 2024
adba820
update
QilongTang Jul 25, 2024
9783743
watch node usage
QilongTang Jul 30, 2024
1fc5aeb
Merge branch 'master' into NodeClusterPlacementPerformance
QilongTang Feb 24, 2025
6e6a5e3
Merge branch 'NodeClusterPlacementPerformance' of https://github.com/…
QilongTang Feb 24, 2025
85fe5da
clean-up
QilongTang Feb 24, 2025
ddf0325
Add back regular node overlay
QilongTang Feb 25, 2025
970c2e2
Add node Glyph for zoom out state
QilongTang Feb 25, 2025
b4a656e
Some minor updates
QilongTang Feb 26, 2025
c96f3ed
update node state image
QilongTang Feb 26, 2025
f46cfe9
update image again
QilongTang Feb 26, 2025
b7a2fe2
Apply new look and feel
QilongTang Feb 26, 2025
2a0a911
code clean up
QilongTang Feb 27, 2025
15f1502
Merge branch 'NodeClusterPlacementPerformance' into NodeClusterVisual
QilongTang Feb 27, 2025
8427140
More comments
QilongTang Feb 27, 2025
efebd42
exclude from graph serialization
QilongTang Feb 28, 2025
f815606
renames
QilongTang Feb 28, 2025
e8f8057
clean up
QilongTang Feb 28, 2025
46f2215
clean up
QilongTang Feb 28, 2025
ac82e1a
Update
QilongTang Feb 28, 2025
1cc20e5
comment
QilongTang Feb 28, 2025
d9975e6
Comments
QilongTang Feb 28, 2025
39f0cd9
Merge branch 'master' into NodeClusterVisual
QilongTang Feb 28, 2025
5e7e3b2
minor update
QilongTang Feb 28, 2025
f719688
Fix unit test and update default flag value
QilongTang Mar 3, 2025
5fb4d4b
Merge branch 'master' into NodeClusterVisual
QilongTang Mar 3, 2025
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
11 changes: 11 additions & 0 deletions src/DynamoCore/Graph/Nodes/NodeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,17 @@ public bool IsFrozen
}
}

/// <summary>
/// A flag indicating whether the node is in transient mode.
/// When a node is in transient mode, the node will not participate in execution,
/// Or saved to the graph. It is only used for previewing the AutoComplete cluster in the canvas.
/// </summary>
public bool IsTransient
{
get;
set;
}

/// <summary>
/// The default behavior for ModelBase objects is to not serialize the X and Y
/// properties. This overload allows the serialization of the X property
Expand Down
4 changes: 2 additions & 2 deletions src/DynamoCore/Graph/Workspaces/SerializationConverters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -862,9 +862,9 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
.Select(outputNode => outputNode.OutputData).ToList();
serializer.Serialize(writer, outputNodeDatas);

// Nodes
// Nodes except for nodes in Transient state
writer.WritePropertyName("Nodes");
serializer.Serialize(writer, ws.Nodes);
serializer.Serialize(writer, ws.Nodes.Where(x => x.IsTransient != true);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This would make sure when node/cluster preview is showing and user press save or shortcut, they dont end up into the dyn


// Connectors
writer.WritePropertyName("Connectors");
Expand Down
2 changes: 2 additions & 0 deletions src/DynamoCore/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,8 @@ Dynamo.Graph.Nodes.NodeModel.InputNodes.get -> System.Collections.Generic.IDicti
Dynamo.Graph.Nodes.NodeModel.IsCustomFunction.get -> bool
Dynamo.Graph.Nodes.NodeModel.IsFrozen.get -> bool
Dynamo.Graph.Nodes.NodeModel.IsFrozen.set -> void
Dynamo.Graph.Nodes.NodeModel.IsPreview.get -> bool
Dynamo.Graph.Nodes.NodeModel.IsPreview.set -> void
Dynamo.Graph.Nodes.NodeModel.IsInErrorState.get -> bool
Dynamo.Graph.Nodes.NodeModel.IsModified.get -> bool
Dynamo.Graph.Nodes.NodeModel.IsPartiallyApplied.get -> bool
Expand Down
4 changes: 2 additions & 2 deletions src/DynamoCore/Scheduler/UpdateGraphAsyncTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,8 @@ protected override TaskMergeInstruction CanMergeWithCore(AsyncTask otherTask)
private static IEnumerable<NodeModel> ComputeModifiedNodes(WorkspaceModel workspace)
{
var nodesToUpdate = new List<NodeModel>();
//Get those modified nodes that are not frozen
foreach (var node in workspace.Nodes.Where(n => n.IsModified && !n.IsFrozen))
//Get those modified nodes that are not frozen or preview states
foreach (var node in workspace.Nodes.Where(n => n.IsModified && !n.IsFrozen && !n.IsTransient))
{
GetDownstreamNodes(node, nodesToUpdate);
}
Expand Down
8 changes: 7 additions & 1 deletion src/DynamoCoreWpf/DynamoCoreWpf.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@
<None Remove="UI\Images\help-16px.png" />
<None Remove="UI\Images\info_48px.png" />
<None Remove="UI\Images\menu_white_48px.png" />
<None Remove="UI\Images\NodeStates\package-64px.png" />
<None Remove="UI\Images\PackageManager\empty-state-first-use-light-gray.png" />
<None Remove="UI\Images\search_icon_20px.png" />
<None Remove="UI\Images\TitleBarButtons\close-darktheme-disabled-16px.png" />
Expand Down Expand Up @@ -161,6 +160,10 @@
<None Remove="UI\Images\NodeStates\frozen-64px.png" />
<None Remove="UI\Images\NodeStates\hidden-64px.png" />
<None Remove="UI\Images\NodeStates\info-64px.png" />
<None Remove="UI\Images\NodeStates\package-64px.png" />
<None Remove="UI\Images\NodeStates\preview-64px.png" />
<None Remove="UI\Images\NodeStates\preview-dark-64px.png" />
<None Remove="UI\Images\NodeStates\preview-light-64px.png" />
<None Remove="UI\Images\TitleBarButtons\close-darktheme-default-16px.png" />
<None Remove="UI\Images\TitleBarButtons\close-darktheme-hover-16px.png" />
<None Remove="UI\Images\TitleBarButtons\close-lighttheme-default-16px.png" />
Expand Down Expand Up @@ -1041,6 +1044,9 @@
<Resource Include="UI\Images\NodeStates\hidden-64px.png" />
<Resource Include="UI\Images\NodeStates\info-64px.png" />
<Resource Include="UI\Images\NodeStates\package-64px.png" />
<Resource Include="UI\Images\NodeStates\preview-64px.png" />
<Resource Include="UI\Images\NodeStates\preview-dark-64px.png" />
<Resource Include="UI\Images\NodeStates\preview-light-64px.png" />
<Resource Include="UI\Images\PackageManager\empty-state-first-use-light-gray.png" />
<Resource Include="UI\Images\question-hover-blue-16px.png" />
<Resource Include="UI\Images\search_icon_20px.png" />
Expand Down
2 changes: 2 additions & 0 deletions src/DynamoCoreWpf/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2435,6 +2435,8 @@ Dynamo.ViewModels.NodeViewModel.IsDisplayingLabels.set -> void
Dynamo.ViewModels.NodeViewModel.IsExperimental.get -> bool
Dynamo.ViewModels.NodeViewModel.IsFrozen.get -> bool
Dynamo.ViewModels.NodeViewModel.IsFrozen.set -> void
Dynamo.ViewModels.NodeViewModel.IsPreview.get -> bool
Dynamo.ViewModels.NodeViewModel.IsPreview.set -> void
Dynamo.ViewModels.NodeViewModel.IsFrozenExplicitly.get -> bool
Dynamo.ViewModels.NodeViewModel.IsInput.get -> bool
Dynamo.ViewModels.NodeViewModel.IsInteractionEnabled.get -> bool
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@

<!-- Nodes -->
<SolidColorBrush x:Key="NodeFrozenOverlayColor" Color="{StaticResource DarkBlue200}" />
<SolidColorBrush x:Key="NodePreviewOverlayColor" Color="#D5BCF7" />
<SolidColorBrush x:Key="NodeInfoColor" Color="{StaticResource Blue300}" />
<SolidColorBrush x:Key="NodeWarningColor" Color="{StaticResource YellowOrange500}" />
<SolidColorBrush x:Key="NodeErrorColor" Color="{StaticResource Red500}" />
Expand Down
42 changes: 36 additions & 6 deletions src/DynamoCoreWpf/ViewModels/Core/NodeViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,8 @@ public bool NodeHoveringState
private static readonly string warningGlyph = "/DynamoCoreWpf;component/UI/Images/NodeStates/alert-64px.png";
private static readonly string errorGlyph = "/DynamoCoreWpf;component/UI/Images/NodeStates/error-64px.png";
private static readonly string infoGlyph = "/DynamoCoreWpf;component/UI/Images/NodeStates/info-64px.png";
private static readonly string previewGlyph = "/DynamoCoreWpf;component/UI/Images/NodeStates/hidden-64px.png";
private static readonly string previewGeometryGlyph = "/DynamoCoreWpf;component/UI/Images/NodeStates/hidden-64px.png";
private static readonly string previewClusterGlyph = "/DynamoCoreWpf;component/UI/Images/NodeStates/preview-light-64px.png";
private static readonly string frozenGlyph = "/DynamoCoreWpf;component/UI/Images/NodeStates/frozen-64px.png";
private static readonly string packageGlyph = "/DynamoCoreWpf;component/UI/Images/NodeStates/package-64px.png";

Expand Down Expand Up @@ -622,6 +623,16 @@ public bool IsFrozen
}
}

/// <summary>
/// Return a value indicating whether this node is in preview state.
/// </summary>
[JsonIgnore]
public bool IsPreview
{
set { NodeModel.IsTransient = value; }
get { return NodeModel.IsTransient; }
}

/// <summary>
/// A flag indicating whether the node is set to freeze by the user.
/// </summary>
Expand Down Expand Up @@ -1302,8 +1313,9 @@ private void BuildErrorBubble()
private static SolidColorBrush infoColor = (SolidColorBrush)(new BrushConverter().ConvertFrom("#6AC0E7"));
private static SolidColorBrush noPreviewColor = (SolidColorBrush)(new BrushConverter().ConvertFrom("#BBBBBB"));
private static SolidColorBrush nodeCustomColor = (SolidColorBrush)(new BrushConverter().ConvertFrom("#B385F2"));
private static SolidColorBrush nodePreviewColor = (SolidColorBrush)(new BrushConverter().ConvertFrom("#BBBBBB"));
private static SolidColorBrush nodePreviewGeometryColor = (SolidColorBrush)(new BrushConverter().ConvertFrom("#BBBBBB"));
private static SolidColorBrush nodeFrozenOverlayColor = (SolidColorBrush)(new BrushConverter().ConvertFrom("#BCD3EE"));
private static SolidColorBrush nodePreviewOverlayColor = (SolidColorBrush)(new BrushConverter().ConvertFrom("#D5BCF7"));
private static SolidColorBrush nodeInfoColor = (SolidColorBrush)(new BrushConverter().ConvertFrom("#6AC0E7"));

/// <summary>
Expand Down Expand Up @@ -1360,10 +1372,10 @@ Pass through all possible states in reverse order

if (!this.IsVisible)
{
result = nodePreviewColor;
result = nodePreviewGeometryColor;
if (result != null)
{
ImgGlyphOneSource = previewGlyph;
ImgGlyphOneSource = previewGeometryGlyph;
}
}

Expand All @@ -1379,7 +1391,7 @@ Pass through all possible states in reverse order
else
{
ImgGlyphOneSource = packageGlyph;
ImgGlyphTwoSource = previewGlyph;
ImgGlyphTwoSource = previewGeometryGlyph;
}
}
}
Expand All @@ -1396,10 +1408,28 @@ Pass through all possible states in reverse order
else
{
ImgGlyphOneSource = frozenGlyph;
ImgGlyphTwoSource = previewGlyph;
ImgGlyphTwoSource = previewGeometryGlyph;
}
}
}

if (this.IsPreview)
{
result = nodePreviewOverlayColor;
if (result != null)
{
if (ImgGlyphOneSource == null)
{
ImgGlyphOneSource = previewClusterGlyph;
}
else
{
ImgGlyphOneSource = previewClusterGlyph;
ImgGlyphTwoSource = previewGeometryGlyph;
}
}
}

if (NodeModel.State == ElementState.Info || NodeModel.State == ElementState.PersistentInfo)
{
result = nodeInfoColor;
Expand Down
36 changes: 33 additions & 3 deletions src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using Dynamo.Controls;
using Dynamo.Graph.Nodes;
using Dynamo.Models;
using Dynamo.Search.SearchElements;
using Dynamo.UI.Commands;
using Dynamo.Utilities;
Expand Down Expand Up @@ -488,6 +486,8 @@ private void AutoComplete(object parameter)
// Handler to invoke Node autocomplete cluster
private void AutoCompleteCluster(object parameter)
{
// Put a C# timer here to test the cluster placement mock
Stopwatch stopwatch = Stopwatch.StartNew();
var wsViewModel = node.WorkspaceViewModel;
wsViewModel.NodeAutoCompleteSearchViewModel.PortViewModel = this;

Expand All @@ -500,12 +500,42 @@ private void AutoCompleteCluster(object parameter)
// Bail out from connect state
wsViewModel.CancelActiveState();

// Create mock nodes, currently Watch nodes (to avoid potential memory leak from Python Editor), and connect them to the input port
var targetNodeSearchEle = wsViewModel.NodeAutoCompleteSearchViewModel.DefaultResults.ToList()[5];
targetNodeSearchEle.CreateAndConnectCommand.Execute(wsViewModel.NodeAutoCompleteSearchViewModel.PortViewModel.PortModel);

var sizeOfMockCluster = 3;
var n = 1;
while (n < sizeOfMockCluster)
{
// Get the last node and connect a new node to it
var node1 = wsViewModel.Nodes.LastOrDefault();
node1.IsPreview = true;
targetNodeSearchEle.CreateAndConnectCommand.Execute(node1.InPorts.FirstOrDefault().PortModel);
n++;
}

wsViewModel.Nodes.LastOrDefault().IsPreview = true;

stopwatch.Stop(); // Stop the stopwatch
wsViewModel.DynamoViewModel.Model.Logger.Log($"Cluster Placement Execution Time: {stopwatch.ElapsedMilliseconds} ms");

// cluster info display in right side panel
if (wsViewModel.DynamoViewModel.IsDNAClusterPlacementEnabled)
{
try
{
MLNodeClusterAutoCompletionResponse results = wsViewModel.NodeAutoCompleteSearchViewModel.GetMLNodeClusterAutocompleteResults();
wsViewModel.OnRequestNodeAutoCompleteViewExtension(results);

// Process the results and display the preview of the cluster with the highest confidence level
// Leverage some API here to convert topology to actual cluster
results.Results.FirstOrDefault().Topology.Nodes.ToList().ForEach(node =>
{
// nothing for now
});

// Display the cluster info in the right side panel
// wsViewModel.OnRequestNodeAutoCompleteViewExtension(results);
}
catch (Exception e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,31 +399,41 @@ internal void ShowNodeAutocompleMLResults()
}
}

foreach (var result in results)
OrganizeConfidenceSection(results);
}
}

/// <summary>
/// Compare to low confidence threadhold defined by user can origanize the results into high and low confidence sections.
/// </summary>
/// <param name="results"></param>
internal void OrganizeConfidenceSection(List<NodeSearchElementViewModel> results)
{
foreach (var result in results)
{
if (result.AutoCompletionNodeMachineLearningInfo.ConfidenceScore >= dynamoViewModel.PreferenceSettings.MLRecommendationConfidenceLevel)
{
if (result.AutoCompletionNodeMachineLearningInfo.ConfidenceScore >= dynamoViewModel.PreferenceSettings.MLRecommendationConfidenceLevel)
{
FilteredHighConfidenceResults = FilteredHighConfidenceResults.Append(result);
}
else {
FilteredLowConfidenceResults = FilteredLowConfidenceResults.Append(result);
}
FilteredHighConfidenceResults = FilteredHighConfidenceResults.Append(result);
}

// Show low confidence section if there are some results under threshold and feature enabled
DisplayLowConfidence = FilteredLowConfidenceResults.Any() && dynamoViewModel.PreferenceSettings.HideNodesBelowSpecificConfidenceLevel;

if (!FilteredHighConfidenceResults.Any())
else
{
DisplayAutocompleteMLStaticPage = true;
AutocompleteMLTitle = Resources.AutocompleteLowConfidenceTitle;
AutocompleteMLMessage = Resources.AutocompleteLowConfidenceMessage;
return;
FilteredLowConfidenceResults = FilteredLowConfidenceResults.Append(result);
}
}

// Show low confidence section if there are some results under threshold and feature enabled
DisplayLowConfidence = FilteredLowConfidenceResults.Any() && dynamoViewModel.PreferenceSettings.HideNodesBelowSpecificConfidenceLevel;

// By default, show only the results which are above the threshold
FilteredResults = dynamoViewModel.PreferenceSettings.HideNodesBelowSpecificConfidenceLevel? FilteredHighConfidenceResults : results ;
if (!FilteredHighConfidenceResults.Any())
{
DisplayAutocompleteMLStaticPage = true;
AutocompleteMLTitle = Resources.AutocompleteLowConfidenceTitle;
AutocompleteMLMessage = Resources.AutocompleteLowConfidenceMessage;
return;
}

// By default, show only the results which are above the threshold
FilteredResults = dynamoViewModel.PreferenceSettings.HideNodesBelowSpecificConfidenceLevel ? FilteredHighConfidenceResults : results;
}

private MLNodeAutoCompletionResponse GetMLNodeAutocompleteResults(string requestJSON)
Expand Down Expand Up @@ -528,7 +538,7 @@ internal void ShowLowConfidenceResults()
}

// Full name and assembly name
private NodeModelTypeId GetInfoFromTypeId(string typeId)
internal NodeModelTypeId GetInfoFromTypeId(string typeId)
{
if (typeId.Contains(','))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,12 +332,12 @@ private void AutoLayoutNodes(object sender, EventArgs e)
var nodeView = (NodeView) sender;
var dynamoViewModel = nodeView.ViewModel.DynamoViewModel;

if (nodeView.ViewModel.NodeModel.OutputNodes.Count() > 0)
if (nodeView.ViewModel.NodeModel.OutputNodes.Count > 0)
{
var originalNodeId = nodeView.ViewModel.NodeModel.OutputNodes.Values.SelectMany(s => s.Select(t => t.Item2)).Distinct().FirstOrDefault().GUID;
var originalNodeId = nodeView.ViewModel.NodeModel.OutputNodes.Values.SelectMany(s => s.Select(t => t.Item2)).Distinct().FirstOrDefault()?.GUID;
dynamoViewModel.CurrentSpace.DoGraphAutoLayout(true, true, originalNodeId);
}
else if (nodeView.ViewModel.NodeModel.InputNodes.Count() > 0)
else if (nodeView.ViewModel.NodeModel.InputNodes.Count > 0)
{
var originalNodeId = nodeView.ViewModel.NodeModel.InputNodes.Values.Select(s => s.Item2).Distinct().FirstOrDefault().GUID;
dynamoViewModel.CurrentSpace.DoGraphAutoLayout(true, true, originalNodeId);
Expand Down
Loading
Loading