From 25cd2aecb19e31907c545bde3312860c7e66f663 Mon Sep 17 00:00:00 2001 From: Deyan Nenov Date: Tue, 3 Dec 2024 15:03:50 +0000 Subject: [PATCH] DYN-7946:PM - crash fix when removing custom nodes with identical names (#15694) --- .../PackageManager/PublishPackageViewModel.cs | 23 +++++++++++-- .../PublishPackageViewModelTests.cs | 33 +++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs b/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs index 4e7783c878a..e238dcd1d9e 100644 --- a/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs @@ -2101,7 +2101,7 @@ private void RemoveItemRecursively(PackageItemRootViewModel packageItemRootViewM } } - private void RemoveSingleItem(PackageItemRootViewModel vm, DependencyType fileType) + internal void RemoveSingleItem(PackageItemRootViewModel vm, DependencyType fileType) { var fileName = vm.DisplayName; @@ -2120,9 +2120,26 @@ private void RemoveSingleItem(PackageItemRootViewModel vm, DependencyType fileTy else if (fileType.Equals(DependencyType.CustomNode) || fileType.Equals(DependencyType.CustomNodePreview)) { fileName = Path.GetFileNameWithoutExtension(fileName); - CustomNodeDefinitions.Remove(CustomNodeDefinitions - .First(x => x.DisplayName == fileName)); + // We allow multiple .dyf files with identical node names to be loaded at once + // We use the node Namespace as a prefix ([Namespace].[Node Name]) to allow for that + string[] nameVariations = { + fileName, + fileName.Replace(".", ""), // Edge case where the actual Display Name as the '.' removed + fileName.Contains('.') ? fileName.Split('.')[1] : fileName // Edge case for the .dyf files that were added first + }; + + foreach (var variation in nameVariations) + { + var customNode = CustomNodeDefinitions.FirstOrDefault(x => x.DisplayName == variation); + if (customNode != null) + { + CustomNodeDefinitions.Remove(customNode); + break; // Exit loop once found and removed + } + } + + // Find and remove the corresponding key in CustomDyfFilepaths var keyToRemove = CustomDyfFilepaths.Keys .FirstOrDefault(k => Path.GetFileNameWithoutExtension(k) == fileName); diff --git a/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs b/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs index cc5987d50a7..eaf6dd7699c 100644 --- a/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs +++ b/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using Dynamo; +using Dynamo.Graph.Nodes; using Dynamo.Graph.Nodes.CustomNodes; using Dynamo.Graph.Workspaces; using Dynamo.PackageManager; @@ -77,6 +78,38 @@ public void SetsErrorState() } + [Test] + public void CanRemoveCustomNodesWithIdenticalNames() + { + var vm = new PublishPackageViewModel(this.ViewModel); + + // Arrange + var customNode1 = new CustomNodeDefinition(Guid.NewGuid(), "Geometry.Curve", new List()); + var customNode2 = new CustomNodeDefinition(Guid.NewGuid(), "Building.Curve", new List()); + var customNode3 = new CustomNodeDefinition(Guid.NewGuid(), "Curve", new List()); + + vm.CustomNodeDefinitions.Add(customNode1); + vm.CustomNodeDefinitions.Add(customNode2); + vm.CustomNodeDefinitions.Add(customNode3); + + // Initial Assert + Assert.AreEqual(3, vm.CustomNodeDefinitions.Count); + + var item1 = new PackageItemRootViewModel("Geometry.Curve.dyf", "C:\\test\\Geometry.Curve.dyf"); + var item2 = new PackageItemRootViewModel("Building.Curve.dyf", "C:\\test\\Building.Curve.dyf"); + var item3 = new PackageItemRootViewModel("Curve.dyf", "C:\\test\\Curve.dyf"); + + // Assert + vm.RemoveSingleItem(item1, DependencyType.CustomNodePreview); + Assert.AreEqual(2, vm.CustomNodeDefinitions.Count); + + vm.RemoveSingleItem(item2, DependencyType.CustomNodePreview); + Assert.AreEqual(1, vm.CustomNodeDefinitions.Count); + + vm.RemoveSingleItem(item3, DependencyType.CustomNodePreview); + Assert.AreEqual(0, vm.CustomNodeDefinitions.Count); + } + [Test] public void CanPublishLateInitializedJsonCustomNode() {